Re: How to loop through characters of a string in D language?

2021-12-08 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 8 December 2021 at 11:23:45 UTC, BoQsc wrote:

Let's say I want to skip characters and build a new string.

The string example to loop/iterate:

```
import std.stdio;

void main()
{
string a="abc;def;ab";

}
```

The character I want to skip: `;`

Expected result:
```
abcdefab
```


import std.stdio : writeln;
import std.algorithm.iteration : filter;
import std.conv : to;

void main()
{
string a = "abc;def;ab";
string b = a.filter!(c => c != ';').to!string;
writeln(b);
}


Re: How to imporve D-translation of these Python list comprehensions ?

2018-01-15 Thread Biotronic via Digitalmars-d-learn

On Monday, 15 January 2018 at 19:05:52 UTC, xenon325 wrote:
I think, most clear code would be with tripple `foreach`, so 
I'll go with that. But probably someone will come up with 
something better and range-ier.


I will admit clarity has suffered, but I like the brevity:

import std.json : JSONValue;
import std.array : array, assocArray;
import std.range : enumerate, byPair;
import std.algorithm : sort, joiner, map, uniq, each;
import std.typecons : tuple;
import std.conv : to;
import std.stdio : writeln;

unittest {
immutable srv1 = ["acs": ["ver": "1.2.3", "rev": "6f2260d"], 
"cms": ["ver": "4.5", "rev": "b17a67e"], "ots": ["ver": "6.7.80", 
"rev": "4f487d2"]];
immutable srv2 = ["acs": ["ver": "1.2.3", "rev": "6f2260d"], 
"cms": ["ver": "5.1", "rev": "2a56c53"], "vaa": ["ver":"0.7", 
"rev": "00852cb"]];

immutable keys = ["rev", "ver"];
immutable srvs = [srv1, srv2];

alias aget = (name, key) => srvs.map!(s => s.get(name, 
[key:""])[key]);
alias bget = (name, key) => aget(name, key).enumerate.map!(b 
=> tuple(key~b.index.to!string, b.value));
alias merge = (aa1, aa2) => (aa2.byPair.each!(kv => 
aa1[kv.key] = kv.value), aa1);


auto result = srvs
.map!(s => s.byKey)
.joiner
.array
.sort
.uniq
.map!(name => merge(keys.map!(key => bget(name, 
key)).joiner.assocArray, ["_name": name]))

.array;

writeln(JSONValue(result).toPrettyString());
}

--
  Simen


Re: How do I set a class member value by its name in a string?

2017-12-27 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 27 December 2017 at 21:42:53 UTC, Mengu wrote:

On Wednesday, 27 December 2017 at 21:39:49 UTC, Mengu wrote:

On Wednesday, 27 December 2017 at 20:54:17 UTC, bitwise wrote:

[...]


there's also a simple workaround for fields with the same 
type: https://run.dlang.io/is/dsFajq


import std.stdio;

struct S {
  int x;
  int y;
}

auto setValue(ref S s, string field, int value) {
  foreach (fieldName; __traits(allMembers, S)) {
if (fieldName == field) {
  __traits(getMember, s, fieldName) = value;
  break;
}
  }
}

void main() {
  S s;
  s.setValue("x", 5);
  s.setValue("y", 25);
  writeln(s);
}


you can play with it to make it more generic. you can also 
create a mixin template that would generate setters for each 
field you would need a setter for and then in the run time 
you'd just be able to call them.


return type should just be void. that's just my muscle memory. 
:-D


More generic, for more better:

void setValue(T, V)(auto ref T aggregate, string field, V value)
{
import std.traits : FieldNameTuple;
import std.meta : Alias;
switch (field)
{
foreach (fieldName; FieldNameTuple!T)
{
case fieldName:
static if (is(typeof(__traits(getMember, 
aggregate, fieldName) = value)))

{
__traits(getMember, aggregate, fieldName) = 
value;

return;
}
else assert(false, T.stringof ~ "."~field~" 
cannot be assigned from a "~V.stringof~".");

}
default:
assert(false, T.stringof ~ " has no field named 
"~field~".");

}
}

unittest {
import std.exception : assertThrown;
import core.exception : AssertError;

static struct S {
int x;
string s;
}

S s;
s.setValue("x", 14);
assert(s.x == 14);
assertThrown!AssertError(s.setValue("q", 14));
assertThrown!AssertError(s.setValue("s", 14));
s.setValue("s", "abc123");
assert(s.s == "abc123");
}

unittest {
import std.exception : assertThrown;
import core.exception : AssertError;

static class C {
int x;
string s;
}

C c = new C;
c.setValue("x", 14);
assert(c.x == 14);
assertThrown!AssertError(c.setValue("q", 14));
assertThrown!AssertError(c.setValue("s", 14));
c.setValue("s", "abc123");
assert(c.s == "abc123");

(new C).setValue("x", 143);
}

--
  Biotronic


Re: BitArray shift left/right confusion.

2017-12-27 Thread Biotronic via Digitalmars-d-learn
On Wednesday, 27 December 2017 at 18:08:19 UTC, Bastiaan Veelo 
wrote:

I suppose the following is not a bug, but confusing it is:

```
void main()
{
import std.stdio;
import std.bitmanip;
BitArray ba = [1, 1, 1, 1, 1, 1, 1, 1];
writeln(ba);// [1, 1, 1, 1, 1, 1, 1, 1]
ba >>= 4; // right shift
writeln(ba);// [1, 1, 1, 1, 0, 0, 0, 0] bits shifted left
}```

I suppose this is because the array is printed left-to-right, 
whereas the bits in a byte are typically ordered right-to-left. 
I suppose I should interpret the bits in the array to increase 
in significance with increasing index (little endian) and that 
right-shift means a shift towards less significance (which is 
to the right in big endian).


The documentation of <<= and >>= [1] however just talks about 
left and right, without defining left and right or clarifying 
that the directions are reversed from how the array is printed.


Is there something I have missed?

[1] 
https://dlang.org/phobos/std_bitmanip.html#.BitArray.opOpAssign.2


BitArray is apparently a mess. As you've pointed out it prints 
the bits in the wrong order. I won't mince words here, since D 
has binary literals on the form 0b1000. Put that in a 
BitArray and print it with the format string "0b%b", and you'll 
get 0b0001. While it may have been intentional, it's bug 
prone and confusing, and so definitely a bug.


It also fucks up royally when it has an exact multiple of 32 bits 
in its buffer, overwriting the last word with 0s when you try and 
shift it in any way.


It also doesn't remove set bits outside of its covered area when 
cast to size_t[]. That is, if I do 
cast(size_t[])(BitArray([1,1,1,1,1,1,1,1]) << 4), the result will 
be something like [4080], which corresponds to 
[0b___].


Lastly (and this is pointed out explicitly in the documentation, 
but still smells if you ask me), it will overwrite bits in the 
words it covers, even if it does not cover those exact bits.


The first two are definitely bugs. The last two are results of 
the intended use case for BitArray, I believe. The documentation 
doesn't explicitly point this out, but it seems BitArray is 
intended to give a bit-by-bit view of an area of memory that is 
actually some other type. Something like this:


struct S {
   int n;
   float f;
}

void foo(ref S s) {
import std.bitmanip;
auto a = BitArray(()[0..1], S.sizeof);
a[7] = true; // Actually sets the corresponding bit in s.
}

--
  Biotronic


Re: Tuple Array Sorting

2017-12-15 Thread Biotronic via Digitalmars-d-learn

On Friday, 15 December 2017 at 17:24:33 UTC, Vino wrote:

Hi Biotronic,

 I was able to find a solution using container array and also 
date formatting, below is the code, please do let me know if 
you find any issue, as i have tested the script and it is 
working as expected.


Program:
import std.algorithm: filter, map, sort, each;
import std.container.array;
import std.file: SpanMode, dirEntries, isDir ;
import std.stdio: writeln,writefln;
import std.typecons: Tuple, tuple;
import std.datetime.systime: SysTime;
import std.conv;
void main () {
auto FFs =  ["C:\\Temp\\sapnas2\\BACKUP", 
"C:\\Temp\\sapnas2\\EXPORT"];

Array!(Tuple!(string, SysTime)) Sorted;
foreach(d; FFs[]) {
auto dFiles = Array!(Tuple!(string, SysTime))(dirEntries(d,


Why specify Array!(Tuple!(string, SysTime)) here? The return 
value from map should be perfectly fine, and if you really want 
an array I'd suggest writing

dirEntries(d, SpanMode.shallow)
.filter!(a => a.isDir)
.map!(a => tuple(a.name, a.timeCreated)))
.array;
It's shorter, easier to read, and the speed difference should be 
miniscule at best. The same comment applies to Sorted, above, 
which could be defined as Tuple!(string, SysTime)[].


SpanMode.shallow).filter!(a => a.isDir).map!(a => tuple(a.name, 
a.timeCreated)));

foreach(i; dFiles[]){ Sorted ~= i; }


No need for a foreach here, you can just do Sorted ~= dFiles.

Sorted[].sort!((a,b) => a[1] > b[1]).each!(e => writefln!"%-63s 
%.20s"(e[0], e[1].to!string));


You seem to be sorting and printing the Sorted array once per 
folder. Going back to [3,5,1], [6,2,4] example, this will print 
1,3,5,1,2,3,4,5,6. That is, it sorts [3,5,1], then prints the 
result. Then it sorts [1,3,5,6,2,4], and prints that. If you move 
the sorting and priting outside the loop (so it's the last line 
before leaving main), you should get the correct result, and and 
not waste time sorting the array multiple times.



}
}


In total, the changes I propose would lead to this code:

import std.algorithm: filter, map, sort, each;
import std.array : array;
import std.file: SpanMode, dirEntries, isDir ;
import std.stdio: writefln;
import std.typecons: Tuple, tuple;
import std.datetime.systime: SysTime;
import std.conv : to;
void main () {
auto FFs =  ["C:\\Temp\\sapnas2\\BACKUP", 
"C:\\Temp\\sapnas2\\EXPORT"];

Tuple!(string, SysTime)[] Sorted;
foreach(d; FFs[]) {
auto dFiles = dirEntries(d, SpanMode.shallow)
.filter!(a => a.isDir)
.map!(a => tuple(a.name, a.timeCreated))
.array;
Sorted ~= dFiles;
}
Sorted[].sort!((a,b) => a[1] > b[1])
.each!(e => writefln!"%-63s %.20s"(e[0], e[1].to!string));
}

--
  Biotronic


Re: overload

2017-12-15 Thread Biotronic via Digitalmars-d-learn

On Thursday, 14 December 2017 at 22:47:15 UTC, dark777 wrote:
I know that this community is not from c ++, but for some time 
I studied how to do overload of ostream operators in c ++ and I 
even managed to get to this result, I got to this result in 
another post done here but I did not understand the that it 
returns this error below:



bin2.cxx:44:43: error: expected ‘,’ or ‘...’ before ‘(’ token
   std::ostream& operator<<(std::ios_base& (__cdecl 
*_Pfn)(std::ios_base&))

   ^
bin2.cxx: In member function ‘std::ostream& 
BinStream::operator<<(std::ios_base&)’:

bin2.cxx:46:16: error: ‘_Pfn’ was not declared in this scope
return os <<_Pfn;


I expect it's confused by __cdecl. I just copied the function 
declaration from VS' iostreams, so it might be tainted by how VS 
does things. Removing __cdecl might work, or just add

#define __cdecl __attribute__((__cdecl__))
A third option is to replace `std::ios_base& (__cdecl 
*Pfn)(std::ios_base&)` with `decltype(std::hex)& Pfn`.


All of this said, I'd suggest finding a C++ forum to get answers 
to these questions. While I'm happy to help, it's not really the 
place for these discussions.


--
  Biotronic


Re: Tuple Array Sorting

2017-12-12 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 12 December 2017 at 15:19:35 UTC, Vino wrote:

import std.algorithm: filter, map, sort;
import std.container.array;
import std.file: SpanMode, dirEntries, isDir ;
import std.stdio: writefln;
import std.typecons: Tuple, tuple;
import std.datetime.systime: SysTime;

void main () {
auto FFs =  ["C:\\Temp\\sapnas2\\BACKUP", 
"C:\\Temp\\sapnas2\\EXPORT", "C:\\Temp\\sapnas2\\PROD_TEAM"];

Array!(Tuple!(string, SysTime)) Result;
foreach(d; FFs[]) {
	auto dFiles = Array!(Tuple!(string, SysTime))(dirEntries(d, 
SpanMode.shallow).filter!(a => a.isDir).map!(a => tuple(a.name, 
a.timeCreated)));

foreach(e; dFiles) { Result ~= e; } }
writefln("%(%-(%-63s %.20s %)\n%)", Result[].sort!((a, b) 
=> a[1] < b[1]));

}


Since there's little need to extract timeCreated and name before 
sorting, here's a version that doesn't:


import std.algorithm : map, filter, sort;
import std.array : array;
import std.range : join;
import std.file : SpanMode, dirEntries, isDir;
import std.stdio : writefln;
import std.typecons : tuple;

void main() {
auto folders = [`C:\Windows`, `C:\Program Files`, `C:\Users`];

auto sorted = folders
.map!(f => f.dirEntries(SpanMode.shallow))
.join
.filter!(e => e.isDir)
.array
.sort!((a,b) => a.timeCreated < b.timeCreated)
.map!(e => tuple(e.name, e.timeCreated.toSimpleString[0 
.. 20]));


writefln("%(%-(%-63s %s %)\n%)", sorted);
}

And a version with normal loops, since the heavily range-based 
version above can be a bit dense. These programs do essentially 
the same thing:


import std.algorithm : sort;
import std.array : array;
import std.file : SpanMode, dirEntries, DirEntry, isDir;
import std.stdio : writefln;
import std.typecons : tuple, Tuple;

void main() {
auto folders = [`C:\Windows`, `C:\Program Files`, `C:\Users`];

DirEntry[] subFolders;

foreach (folder; folders) {
auto children = dirEntries(folder, SpanMode.shallow);
foreach (child; children) {
if (child.isDir) subFolders ~= child;
}
}

subFolders.sort!((a,b) => a.timeCreated < b.timeCreated);
Tuple!(string, string)[] interestingParts;

foreach (subFolder; subFolders) {
interestingParts ~= tuple(subFolder.name, 
subFolder.timeCreated.toSimpleString[0..20]);

}

writefln("%(%-(%-63s %s %)\n%)", interestingParts);
}

As you can see, I'm just chopping off the parts I don't like from 
toSimpleString. It seems a good format function for dates does 
not exist in Phobos.


--
  Biotronic


Re: operator overload

2017-12-12 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 12 December 2017 at 16:54:17 UTC, Biotronic wrote:
There is no way in C++ to set the format the way you want it. 
If you want binary output, you need to call a function like 
your binario function.


Of course this is not entirely true - there is a way, but it's 
ugly and probably not what you want:


struct BinStream
{
std::ostream& os;
BinStream(std::ostream& os) : os(os) {}

template
BinStream& operator<<(T&& value)
{
os << value;
return *this;
}

BinStream& operator<<(int value)
{
os << binario(value);
return *this;
}

std::ostream& operator<<(std::ios_base& (__cdecl 
*_Pfn)(std::ios_base&))

{
return os << _Pfn;
}
};

struct Bin
{
friend BinStream operator<<(std::ostream& os, const Bin& 
f);

} bin;

BinStream operator<<(std::ostream& os, const Bin& f)
{
return BinStream(os);
}

int main()
{
std::cout << "\n\t127 em binario: " << binario(127)
<< "\n\t127 em binario: " << bin << 127
<< "\n\t127 em octal:   " << std::oct << 127
<< "\n\t127 em binario: " << bin << 127
<< "\n\t127 em hexadecimal: " << std::hex << 127
<< "\n\t127 em binario: " << bin << 127
<< "\n\t127 em decimal: " << std::dec << 127
<< "\n\t127 em binario: " << bin << 127 << "\n\n";
}

What is this black magic? Instead of overriding how std::ostream 
does formatting, Bin::Operator<< now returns a wrapper around a 
std::ostream, which special cases ints. If it gets any other 
format specifiers, it returns the ostream again, and the binary 
formatting is gone.


All in all, I think the conclusion is: Stay with D.

--
  Biotronic


Re: operator overload

2017-12-12 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 12 December 2017 at 15:52:09 UTC, dark777 wrote:
I know that this community is not of c ++, but some time I have 
been studying how to do overload of ostream operators in c ++ 
and I even managed to get to this result but the same is not 
converting to binary only presents zeros as output to any 
number already tried to pass parameter of variable and yet he 
is not getting the number for conversion how to solve it so 
that it works correctly?


PS: if I use the same conversion algorithm in a function it 
converts normally it is not only converting to the output of 
the operator ..



https://pastebin.com/BXGXiiRk


This line:
<< "\n\t127 em binario: " << bin << 127 << "\n\n";

Your hope is that the '<< bin' part should behave just like 
std::hex does, except binary instead of hex. Right?


I'm afraid that's not how C++ formatting works. You can see a 
hint of what happens in the output you get:

127 em binario: 127

The zeroes are from the uninitialized int in your Bin struct, and 
the '127' is from the 127 you pass right after passing bin.


Translating to code that does not use operators, the behavior you 
expect is something like this:


std::cout.print("\n\t127 em binario: ");
std::cout.setFormat(bin);
std::cout.print(127); // Should use bin for formatting
std::cout.print("\n\n");

The actual behavior is something like this:

std ::cout.print("\n\t127 em binario: ");
std::cout.print(bin); // Prints the value stored in bin. That 
is, 0.
std::cout.print(127); // Prints 127 just the way it would 
otherwise print it.

std::cout.print("\n\n");

There is no way in C++ to set the format the way you want it. If 
you want binary output, you need to call a function like your 
binario function.


The point of overloading operator<<(std::ostream&, MyType) is not 
to format another type, but to be able to print MyType in a given 
way. Basically like toString() in D, C# or Java.


--
   Biotronic


Re: Tuple Array Sorting

2017-12-11 Thread Biotronic via Digitalmars-d-learn

On Monday, 11 December 2017 at 19:46:04 UTC, Vino wrote:


import std.algorithm;
import std.container.array;
import std.file: SpanMode, dirEntries, isDir ;
import std.stdio: writefln, writeln;
import std.typecons: Tuple, tuple;
import std.range: chain;

void main () {
auto FFs =  ["C:\\Temp\\BACKUP", "C:\\Temp\\EXPORT", 
"C:\\Temp\\PROD_TEAM"];

foreach(d; FFs[]) {
auto dFiles = Array!(Tuple!(string, SysTime))(dirEntries(d, 
SpanMode.shallow).filter!(a => a.isDir).map!(a => tuple(a.name, 
a.timeCreated)));
writefln("%(%-(%-63s %s %)\n%)", chain(dFiles[]).sort!((a, b) 
=> a[1] < b[1]));

}
}


So let's go through this code then, shall we?

Edited a bit for clarity:

// For each directory (*one at a time*),
foreach(d; FFs[]) {
// List all the folders
auto dFiles = Array!(Tuple!(string, SysTime))(
dirEntries(d, SpanMode.shallow)
// Not the files,
.filter!(a => a.isDir)
// Grab only the information we want,
.map!(a => tuple(a.name, a.timeCreated)));
// And print a sorted list of the subfolders of the 
current folder.
writefln("%(%-(%-63s %s %)\n%)", 
chain(dFiles[]).sort!((a, b) => a[1] < b[1]));

}

This will go through C:\Temp\BACKUP, and display a sorted list of 
all the subfolders in that folder. Then it will do the same for 
C:\Temp\EXPORT, and then for C:\Temp\PROD_TEAM.


No subfolder of C:\Temp\PROD_TEAM will be displayed before 
anything in C:\Temp\BACKUP, because you're sorting only one set 
of subfolders at a time.


What you're essentially doing, is sorting [6,2,4] and [3,5,1] 
separately, and printing them separately, giving the illusion of 
having sorted them into the array [2,4,6,1,3,5]. As you correctly 
point out, this is not what you wanted. The code I presented 
avoids this by joining the lists for all the folders.


Your code could also be simplified a bit - there's no need for 
the call to chain, and calling dirEntries.filter.map.array is 
easier to read and write than having Array!(Tuple!(string, 
SysTime)) at the front.


In case my code from earlier was hard to understand, here's 
another version~, more closely modeled to your code:


import std.algorithm : map, filter, sort;
import std.array : array;
import std.file : SpanMode, dirEntries, isDir;
import std.stdio : writefln;
import std.typecons : Tuple, tuple;
import std.datetime : SysTime;

void main() {
// The folders we want to look in.
auto folders = [`C:\Windows`, `C:\Program Files`, `C:\Users`];

// We'll put all the subfolders we find here, so we can sort 
them in the end.

Tuple!(string, SysTime)[] subFolders;

// Look through each folder in turn.
foreach (folder; folders) {
// Get all entries in the folder,
auto entries = dirEntries(folder, SpanMode.shallow);
// Get rid of files,
auto folderEntries = entries.filter!(a => a.isDir);
// Grab the interesting parts,
auto interestingParts = folderEntries.map!(a => 
tuple(a.name, a.timeCreated));

// And add it to the array.
subFolders ~= interestingParts.array;
}
// Sort the entire array.
auto sorted = subFolders.sort!((a, b) => a[1] < b[1]);
// And print it!
writefln("%(%-(%-63s %s %)\n%)", sorted);
}


Re: Tuple Array Sorting

2017-12-11 Thread Biotronic via Digitalmars-d-learn

On Monday, 11 December 2017 at 15:33:08 UTC, Vino wrote:

On Monday, 11 December 2017 at 15:15:47 UTC, Biotronic wrote:

On Monday, 11 December 2017 at 14:52:35 UTC, Vino wrote:

Example Program and Output

import std.algorithm: filter, map, sort;
import std.container.array;
import std.file: SpanMode, dirEntries, isDir ;
import std.range: chain;
import std.stdio: writefln;
import std.typecons: Tuple, tuple;

void main () {
auto FFs =  Array!(string)("C:\\Temp\\BACKUP", 
"C:\\Temp\\EXPORT", "C:\\Temp\\PROD_TEAM");

int AgeSize = 2;
foreach(d; FFs[]) {
auto dFiles = Array!(Tuple!(string, string))(dirEntries(d, 
SpanMode.shallow).filter!(a => a.isDir).map!(a => 
tuple(a.name, a.timeCreated.toSimpleString[0 .. 20])));
writefln("%(%-(%-63s %s %)\n%)", chain(dFiles[]).sort!((a,b) 
=> a[0] > b[0]));

}
}


You're somewhat close. You're sorting based on the 0th element 
of your tuples, while you should sort on the 1st. Something 
like this:


import std.algorithm: filter, map, sort;
import std.array : array;
import std.file: SpanMode, dirEntries, isDir ;
import std.range: join;
import std.stdio: writefln;
import std.typecons: tuple;

void main () {
auto folders =  ["D:\\Dev"];

auto sorted = folders
.map!(a => dirEntries(a, SpanMode.shallow))
.join
.filter!(a => a.isDir)
.map!(a => tuple(a.name, 
a.timeCreated.toSimpleString[0 .. 20]))

.array
.sort!((a,b) => a[1] > b[1]);

writefln("%( %( %-63s %s %) \n%)", sorted);
}

--
  Biotronic


Hi,

 I tired that but no luck, below is the output, in your code 
you have one folder "auto folders =  ["D:\\Dev"];" if you have 
multiple folder then output is not sorted.


C:\Temp\BACKUP\dir2 
2017-Sep-09 22:44:11
C:\Temp\BACKUP\dir1 
2017-Sep-06 16:06:42
C:\Temp\BACKUP\DND3 
2017-Sep-05 14:31:00
C:\Temp\BACKUP\t1   
2017-Dec-11 04:10:02
C:\Temp\BACKUP\dir3 
2017-Dec-10 06:56:07
C:\Temp\EXPORT\DND6 
2017-Sep-05 14:31:00
C:\Temp\PROD_TEAM\DND1  
2017-Sep-05 14:31:01


Are you sure that's the output from my code? Let's step through 
the code:


// Iterating over folders:
folders
// Create a range where each element is a range of DirEntry
// in the given folder.
.map!(a => dirEntries(a, SpanMode.shallow))
// Join these together to a single range of DirEntry instead 
of

// a range-of-ranges-of-DirEntry.
.join
// Remove anything that's not a folder.
.filter!(a => a.isDir)
// Grab the information we actually care about.
.map!(a => tuple(a.name, a.timeCreated))
// Enumerate to an array, so we can sort it.
.array
// Sort this array by the second tuple element (timeCreated).
.sort!((a,b) => a[1] > b[1]);

If this code does not do what you're asking, there's a bug 
outside of the code, probably in the standard library.


If instead you are invoking the program multiple times with a 
single folder each time, the output you describe is to be 
expected.


Apart from that, I'm not sure what could be wrong.

--
  Biotronic


Re: Tuple Array Sorting

2017-12-11 Thread Biotronic via Digitalmars-d-learn

On Monday, 11 December 2017 at 15:33:08 UTC, Vino wrote:
 I tired that but no luck, below is the output, in your code 
you have one folder "auto folders =  ["D:\\Dev"];" if you have 
multiple folder then output is not sorted.


Works on my machine. Of course, since time toSimpleString returns 
non-ISO8601, the sorting might not make perfect sense 
("2017-Dec-12" < "2017-Jan-01"). Testing with multiple folders 
gives perfectly sorted output. If you want it sorted by date 
instead of by string representation of date, feel free to remove 
.toSimpleString[0 .. 20].


--
  Biotronic


Re: Tuple Array Sorting

2017-12-11 Thread Biotronic via Digitalmars-d-learn

On Monday, 11 December 2017 at 14:52:35 UTC, Vino wrote:

Example Program and Output

import std.algorithm: filter, map, sort;
import std.container.array;
import std.file: SpanMode, dirEntries, isDir ;
import std.range: chain;
import std.stdio: writefln;
import std.typecons: Tuple, tuple;

void main () {
auto FFs =  Array!(string)("C:\\Temp\\BACKUP", 
"C:\\Temp\\EXPORT", "C:\\Temp\\PROD_TEAM");

int AgeSize = 2;
foreach(d; FFs[]) {
auto dFiles = Array!(Tuple!(string, string))(dirEntries(d, 
SpanMode.shallow).filter!(a => a.isDir).map!(a => tuple(a.name, 
a.timeCreated.toSimpleString[0 .. 20])));
writefln("%(%-(%-63s %s %)\n%)", chain(dFiles[]).sort!((a,b) => 
a[0] > b[0]));

}
}


You're somewhat close. You're sorting based on the 0th element of 
your tuples, while you should sort on the 1st. Something like 
this:


import std.algorithm: filter, map, sort;
import std.array : array;
import std.file: SpanMode, dirEntries, isDir ;
import std.range: join;
import std.stdio: writefln;
import std.typecons: tuple;

void main () {
auto folders =  ["D:\\Dev"];

auto sorted = folders
.map!(a => dirEntries(a, SpanMode.shallow))
.join
.filter!(a => a.isDir)
.map!(a => tuple(a.name, a.timeCreated.toSimpleString[0 
.. 20]))

.array
.sort!((a,b) => a[1] > b[1]);

writefln("%( %( %-63s %s %) \n%)", sorted);
}

--
  Biotronic


Re: Optimizing a bigint fibonacci

2017-12-06 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 6 December 2017 at 10:16:16 UTC, helxi wrote:

On Wednesday, 6 December 2017 at 10:00:48 UTC, Biotronic wrote:

AliasSeq!(a, b) = tuple(
a * (2*b - a),
a*a + b*b);

[...]


Nice. But why the AliasSeq?


Just playing around a bit. The alternative is to assign to a 
temporary:


   auto c = a * (2*b - a);
   b = a*a + b*b;'
   a = c;

The resulting behavior is the same, and apart from the cludgy 
names I kinda like doing (a,b) = (c,d).


--
  Biotronic


Re: Optimizing a bigint fibonacci

2017-12-06 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 6 December 2017 at 09:12:08 UTC, helxi wrote:
This is question not directly related to language concepts, 
it's got more to do with the application. I would appreciate if 
anyone would point to me how I could optimize this bit of code


Here's my version:, based on fast squaring:

auto fib(ulong n) {
import std.bigint : BigInt;
import std.meta : AliasSeq;
import std.typecons : tuple;
BigInt a = 0;
BigInt b = 1;
auto bit = 63;
while (bit > 0) {
AliasSeq!(a, b) = tuple(
a * (2*b - a),
a*a + b*b);

if (n & (BigInt(1) << bit)) {
AliasSeq!(a, b) = tuple(b, a+b);
}
--bit;
}
return a;
}

unittest {
import std.stdio : writeln;
import std.datetime : MonoTime;

auto t0 = MonoTime.currTime;
writeln(fib(10_000_000));
writeln(MonoTime.currTime - t0);
}

Takes around 600 milliseconds to compute fib(1_000_000), and 50 
seconds for fib(10_000_000).


Fast squaring algorithm found and described here:
https://www.nayuki.io/page/fast-fibonacci-algorithms

I also noticed that if I try to compute it in the compile time 
with enum x = fib(10) the compiler freezes. What could 
cause this?


That's because the poor compiler isn't as good at optimizing 
compile-time code as run-time code, and because fib(10) is 
frigging ginormous.


--
  Biotronic


Re: Sort characters in string

2017-12-06 Thread Biotronic via Digitalmars-d-learn
On Wednesday, 6 December 2017 at 08:59:09 UTC, Fredrik Boulund 
wrote:

string word = "longword";
writeln(sort(word));

But that doesn't work because I guess a string is not the type 
of range required for sort?


Yeah, narrow (non-UTF-32) strings are not random-access, since 
characters like  take up more than one code unit, and so ""[0] 
returns an invalid piece of a character instead of a  full 
character.


In addition, sort does in-place sorting, so the input range is 
changed. Since D strings are immutable(char)[], changing the 
elements is disallowed. So in total, you'll need to convert from 
a string (immutable(char)[]) to a dchar[]. std.conv.to to the 
rescue:


import std.stdio : writeln;
import std.conv : to;
import std.algorithm.sorting : sort;

string word = "longword";
writeln(sort(word.to!(dchar[]))); // dglnoorw

--
  Biotronic


Re: cannot deduce template lambda from argument

2017-12-06 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 5 December 2017 at 23:01:43 UTC, aliak wrote:

immutable lambda(T) = (T n) => n * n;


Generally, you'd want to write

alias lambda = n => n * n;

instead. That said, I don't see any reason why your syntax 
shouldn't work, and would argue it's a bug. Please file it in 
Bugzilla.


--
  Biotronic


Re: Turn a float into a value between 0 and 1 (inclusive)?

2017-11-21 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 21 November 2017 at 09:21:29 UTC, Chirs Forest wrote:
I'm interpolating some values and I need to make an 
(elapsed_time/duration) value a float between 0 and 1 
(inclusive of 0 and 1). The elapsed_time might be more than the 
duration, and in some cases might be 0 or less. What's the most 
efficient way to cap out of bounds values to 0 and 1? I can do 
a check and cap them manually, but if I'm doing a lot of these 
operations I'd like to pick the least resource intensive way.


Good old comparisons should be plenty in this case:

T clamp(T)(T value, T min, T max) {
return value < min ? min : value > max ? max : value;
}

That's two comparisons and two conditional moves. You're not 
gonna beat that.


Also, if I wanted out of bounds values to wrap (2.5 becomes 
0.5) how would I get that value and also have 1.0 not give me 
0.0?


As Petar points out, this is somewhat problematic. You think of 
the codomain (set of possible results) as being the size (1.0 - 
0.0) = 1.0. However, since you include 1.0 in the set, the size 
is actually 1.0 + ε, which is very slightly larger. You could use 
a slightly modified version of Petar's function:


T zeroToOne(T)(T val) { return val % (1+T.epsilon); }

However, this induces rounding errors on larger numbers. e.g. 1.0 
+ ε becomes 0, while you'd want it to be ε.


I guess I should ask for some clarification - what would you 
expect the return value to be for 2.0? Is that 0.0 or 1.0? How 
about for -1.0?


A simple function that does give the results you want between 0.0 
and 1.0 (inclusive) is this:


T zeroToOne(T)(T val) {
if (val >= 0 && val <= 1.0) {
return val;
}
return val % 1;
}

The problem now, however, is that zeroToOne gives negative 
results for negative values. This is probably not what you want. 
This can be fixed with std.math.signbit:


T zeroToOne(T)(T val) {
import std.math : signbit;
if (val >= 0 && val <= 1.0) {
return val;
}
return (val % 1) + val.signbit;
}

If you're willing to give up the last 1/8388608th of precision 
(for float, 1/4503599627370496th for double) that including 1.0 
gives you, this can become:


T zeroToOne(T)(T val) {
import std.math : signbit;
return (val % 1) + val.signbit;
}

Which is easier to read, and consistent for values outside the 
[0,1) interval.


--
  Biotronic


Re: Missing return value error not present with template

2017-11-15 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 15 November 2017 at 08:43:01 UTC, Tony wrote:
Error: function test_warnings.MyClass.SomeMethod has no return 
statement, but is expected to return a value of type int


but if I make it a template class:

class MyClass(T) {

there is no compile error. I don't know why the error isn't 
given for the template code as well.


As Andrea points out, it's because it's a template. There are 
reasons for this that may not be immediately obvious, though. 
Static if is one:


class Foo(T) {
int bar() {
   static if (is(T == int)) {
   return 0;
   } else static if (is(T == string)) {
   return 1;
   }
}
}

In the general case, bar() would be missing a return statement. 
However, if the only uses are when T is either a string or an 
int, that's no problem, since the failure case doesn't see use.


Another example is mixins:

class Foo(string s) {
int bar() {
mixin(s);
}
}

The compiler now has absolutely no idea what bar() might or might 
not return, until s is specified. If s is "return 3;", 
everything's hunky-dory. If it's "return string.init;", bar will 
fail to compile. It's reasonable for the type to only accept 
correct code, so this is a non-problem in practice.


Next up, overloads:

class Foo(T) {
int bar() {
return baz(T.init);
}
}

int baz(int n) {
return n;
}

void baz(string s) {}

Members of the template argument:

class Foo(T) {
int bar() {
T.baz();
}
}

There's plenty other cases where the compiler simply cannot tell 
if the code is invalid without instantiating the template, and 
where it's valid in some cases but not others. There are other 
languages that require the equivalent of template parameters to 
conform to some defined meta-type, and there are benefits to both 
sides of that discussion. D has chosen to go the loosely (or 
duck-) typed way, and I feel it's a good match for the rest of 
the language.


--
  Biotronic


Re: Disabled and enabled copy constructors and .dup

2017-10-24 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 24 October 2017 at 11:37:42 UTC, Per Nordlöw wrote:

On Tuesday, 24 October 2017 at 07:56:34 UTC, Biotronic wrote:

struct SuppressPostblit(T)
{
// Disguise T as a humble array.
private ubyte[T.sizeof] _payload;
...


A bit too hackish for my taste, but does the job still.

Thanks.


Cleaned up and slightly less hackish (yeah, it bothered me too):

enum SuppressOptions {
destructor = 1,
postblit = 2
}

struct Suppress(T, SuppressOptions options) if (options != 0)
{
import std.traits : isCopyable;
private enum suppressPostblit   = (options & 
SuppressOptions.postblit)   != 0;
private enum suppressDestructor = (options & 
SuppressOptions.destructor) != 0;
private enum postblitName = __traits(hasMember, T, 
"__xpostblit") ? "__xpostblit" : "__postblit";


// Disguise T as a humble array.
private ubyte[T.sizeof] _payload;

// Create from instance of T.
this(T arg) {
_payload = *cast(ubyte[T.sizeof]*)
}

// Or forward constructor arguments to T's constructor.
static if (__traits(hasMember, T, "__ctor"))
{
this(Args...)(Args args)
if (__traits(compiles, (Args e){__traits(getMember, 
T.init, "__ctor")(e);}))

{
__traits(getMember, get, "__ctor")(args);
}
}

// Call dtor
static if (!suppressDestructor) {
~this() {
destroy(get);
}
}

// Call postblit
static if (!suppressPostblit) {
static if (!isCopyable!T) {
@disable this(this);
} else static if (__traits(hasMember, T, postblitName)) {
this(this) {
__traits(getMember, get, postblitName)();
}
}
}

// Pretend to be a T.
@property
ref T get()
{
return *cast(T*)_payload.ptr;
}

alias get this;
}

struct S1 {
@disable this(this);
~this() {
throw new Exception("Don't touch my destructor!");
}
}

unittest {
import std.exception;
static assert(!__traits(compiles, (Suppress!S1 a) { auto b = 
a; }));
static assert(__traits(compiles, (Suppress!(S1, 
SuppressOptions.postblit) a) { auto b = a; }));


assertThrown({ Suppress!(S1, SuppressOptions.postblit) a; 
}());
assertNotThrown({ Suppress!(S1, SuppressOptions.postblit | 
SuppressOptions.destructor) a; }());

}

--
  Biotronic


Re: Disabled and enabled copy constructors and .dup

2017-10-24 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 24 October 2017 at 07:33:43 UTC, Per Nordlöw wrote:
If I have a `struct X` (container in my case) with disabled 
copying (postblit) and instead a .dup property, is it somehow 
possible, unsafe or not, to have `X` as a member of another 
`struct Y` with an enabled copy constructor which calls `X.dup`?


With the same approach outline in 
https://forum.dlang.org/post/nakguitssvjdclpgw...@forum.dlang.org, it is indeed possible. In fact, simply using SuppressGC!X should enable it. Note however, that since the point of SuppressGC is to not call the object's destructor (and thus its name is poorly chosen by yours truly), you will need to do so explicitly. Updating the approach to only suppress postblits:


struct SuppressPostblit(T)
{
// Disguise T as a humble array.
private ubyte[T.sizeof] _payload;

// Create from instance of T.
this(T arg) {
_payload = *cast(ubyte[T.sizeof]*)
}

// Or forward constructor arguments to T's constructor.
static if (__traits(hasMember, T, "__ctor"))
{
this(Args...)(Args args)
if (__traits(compiles, (Args e){__traits(getMember, 
T.init, "__ctor")(e);}))

{
__traits(getMember, get, "__ctor")(args);
}
}

// Pretend to be a T.
@property
ref T get()
{
return *cast(T*)_payload.ptr;
}

alias get this;

static if (__traits(hasMember, T, "__dtor")) {
~this() {
__traits(getMember, get, "__dtor")();
}
}
}

--
  Simen


Re: Skynet 1M Fiber microbenchmark in D

2017-10-18 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 18 October 2017 at 12:32:31 UTC, Nordlöw wrote:
Further, are we forced to use the GC for Fiber allocation or 
can a sub-class of Fibers implement its own allocation strategy?


Afraid it's set in stone. Now, it doesn't actually use the GC for 
allocating the stack memory, instead opting for VirtualAlloc on 
Windows and mmap, valloc or malloc on other platforms. Of course, 
it's possible to change the implementation in core.thread, but 
it's probably more work than you want. Copying the entire Fiber 
class and changing it also runs into some problems, since it 
depends on private stuff in core.thread.


--
  Biotronic


Re: Skynet 1M Fiber microbenchmark in D

2017-10-18 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 18 October 2017 at 11:34:57 UTC, Nordlöw wrote:
Another thing...how should the synchronization between the 
fibers figure out when the total number of fibers have reached 
one million?...via an atomic counter fed by reference to the 
constructor...or are there better ways? Because I do need an 
atomic reference counter here, right?


This is how I did it:
import core.thread : Fiber;

class MyFiber : Fiber {
int _depth;
ulong _index;
ulong _value;

this(int depth, ulong index) {
super();
_depth = depth;
_index = index;
}

void run() {
if (_depth == 6) { // 10^6 == 1 million, so stop here.
_value = _index;
return;
}

_value = 0;
foreach (i; 0..10) { // Line 23
auto e = new MyFiber(_depth+1, _index * 10 + i);
e.call();
_value += e._value;
}
}
}

unittest {
import std.stdio : writeln;
import std.datetime.stopwatch : StopWatch, AutoStart;
auto sw = StopWatch(AutoStart.yes);
auto a = new MyFiber(0, 0);
a.call();
sw.stop();
assert(a._value == 4950);
writeln(a._value, " after ", sw.peek);
}


And how do I parallelize this over multiple worker threads? 
AFAICT fibers are by default all spawned in the same main 
thread, right?


True. Well, they're not really spawned on any thread - they're 
allocated on the heap, have their own stack, and are run on 
whichever thread happens to invoke their call() method.


I experimented a little bit with parallelism, and the easiest 
definitely is to replace line 23 with this:


foreach (i; taskPool.parallel(10.iota, 1)) {

It seems to make very little difference in terms of run time, 
though. I tried using a mix of these approaches - parallel at low 
depth, basically just to fill up the cores, and serial closer to 
the leaves. The difference is still negligible, so I assume the 
losses are elsewhere.


--
  Biotronic


Re: Making template instantiations more lazy

2017-10-18 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 18 October 2017 at 10:55:49 UTC, Per Nordlöw wrote:
On Wednesday, 18 October 2017 at 10:36:41 UTC, Per Nordlöw 
wrote:

Yeah I've thought of that.

I still would like to have it built-in to the compiler.


Would such a change cause any serious breakage?


Seems unlikely - when did you last use a function without using 
it? :p


I'm not actually sure why D behaves this way - C++ doesn't. I 
guess there is some value as tests - instantiating the type tests 
that all its methods compile. Not actually sure that's more of a 
positive than a negative, but it's certainly never bothered me.


--
  Biotronic


Re: Skynet 1M Fiber microbenchmark in D

2017-10-18 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 18 October 2017 at 11:01:56 UTC, Per Nordlöw wrote:
On Wednesday, 18 October 2017 at 09:01:30 UTC, Per Nordlöw 
wrote:
Creates an actor (goroutine, whatever), which spawns 10 new 
actors, each of them spawns 10 more actors, etc. until one 
million actors are created on the final level. Then, each of 
them returns back its ordinal number (from 0 to 99), which 
are summed on the previous level and sent back upstream, until 
reaching the root actor. (The answer should be 4950).


See also: https://github.com/atemerev/skynet


I Fibers aren't supposed to take any parameters how are we 
supposed to pass values to it during creation?


class MyFiber : Fiber {
this(int arguments, string go, float here) {
super();
// Save arguments somewhere
}
void run() {
// Use arguments here.
}
}

--
  Biotronic


Re: Making template instantiations more lazy

2017-10-18 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 18 October 2017 at 09:56:33 UTC, Nordlöw wrote:
On Wednesday, 18 October 2017 at 09:32:39 UTC, Jonathan M Davis 
wrote:
On Wednesday, October 18, 2017 09:13:47 Per Nordlöw via 
Digitalmars-d-learn wrote:
Are there any nearby plans to make more template 
instantiations (especially aggregate members) lazy in DMD?


Are there any specific obstacles against doing that or has it 
just not been prioritized?


Templates are never instantiated unless they're actually... 
well, instantiated. So, they're already lazy in that sense. 
The compiler isn't pre-emptive with them at all. What exactly 
about them do you want to be lazy that isn't?


- Jonathan M Davis


Member functions of templated containers is my main focus.


Make them templates, that should solve the problem:

struct S(T) {
void foo()() {
compileerror;
}
}


Re: testing if data is allocated on the stack or heap

2017-10-18 Thread Biotronic via Digitalmars-d-learn
It's worth pointing out, btw, that the main reason for this code 
is to help drug diagnose his or her problem, not to be the 
be-all, end-all of stack identifying functions. :)


It will of course not correctly identify pointers to variables on 
other threads' stacks, and fiber stacks probably trip it up bad.


--
  Biotronic


Re: testing if data is allocated on the stack or heap

2017-10-18 Thread Biotronic via Digitalmars-d-learn
On Tuesday, 17 October 2017 at 23:59:19 UTC, Steven Schveighoffer 
wrote:

On 10/17/17 7:32 PM, flamencofantasy wrote:

On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:

On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:

[...]


I have very little knowledge about sbrk, so here's my 
solution.


Tested on win32 and win64.

[...]


Try this;

unittest {
     int[5*1024] n;
     int* p = new int;

     assert(n.onStack);
     assert(!p.onStack);
}


The second is wrong. You are asserting that the storage of p is 
not on the stack, but it is.


What p *points at* is not on the stack.

So the correct call should be:

assert(!(*p).onStack);

or (IMO) less ugly: assert(!onStack(*p));

-Steve


No, the second is correct - the ref overload is only chosen when 
p is not implicitly castable to void*. In fact, the second assert 
passes, it's the first one that causes problems.


I've written an improved version, that probably still has 
problems. If flamencofantasy would like to point out other 
shortcomings, I'd love to learn.


module stackCheck;

private size_t stackStart;
enum size_t pageSize = 0x1000;

static this() {
import core.stdc.stdlib : alloca;
stackStart = cast(size_t)alloca(size_t.sizeof);
}

bool onStack(void* p) {
size_t end = cast(size_t)
size_t pp = cast(size_t)p;
size_t ss = stackStart;

if (end > ss) {
end &= ~(pageSize-1);
ss  &= ~(pageSize-1);
end += pageSize;
return pp >= ss && pp <= end;
} else {
end &= ~(pageSize-1);
ss  &= ~(pageSize-1);
ss += pageSize;
return pp <= ss && pp >= end;
}
}

bool onStack(T)(ref T p) {
return ().onStack;
}

unittest {
int n;
int* p = new int;

assert(n.onStack);
assert(!p.onStack);
}

unittest {
int[5*1023] n;
int* p = new int;

assert(n.onStack);
assert(!p.onStack);
}


Re: testing if data is allocated on the stack or heap

2017-10-17 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
My code fails and I guess the reason is I have a slice to data 
in the stack and it becomes garbage in some moment. So I need a 
way to check where data is placed. Is it right that it can be 
done in linux using `sbrk` so that if the addr of data is less 
than `sbrk(0)` returning then data is on the stack and on the 
heap in other case?


I have very little knowledge about sbrk, so here's my solution.

Tested on win32 and win64.

module stackCheck;

private size_t stackStart;
enum size_t pageSize = 0x1000;

static this() {
import core.stdc.stdlib : alloca;
stackStart = cast(size_t)alloca(size_t.sizeof) & 
~(pageSize-1);

}

bool onStack(void* p) {
size_t end = (cast(size_t) & ~(pageSize-1)) + pageSize;
size_t pp = cast(size_t)p;

if (end > stackStart) {
return pp >= stackStart && pp <= end;
} else {
return pp <= stackStart && pp >= end;
}
}

bool onStack(T)(ref T p) {
return ().onStack;
}

unittest {
int n;
int* p = new int;

assert(n.onStack);
assert(!p.onStack);
}

--
  Biotronic


Re: partiallyQualifiedName?

2017-10-17 Thread Biotronic via Digitalmars-d-learn

On Monday, 16 October 2017 at 23:56:00 UTC, Nicholas Wilson wrote:

using fullyQualifiedName [here]
(https://github.com/libmir/dcompute/blob/master/source/dcompute/driver/ocl/util.d#L120)
leads to a large compilation slowdown, but I only need it to 
disambiguate up to the module level i.e. so that


struct Context
{
enum Properties {}
static struct Info
{
@(0) Properties p; // <---
}
}

...
partiallyQualifiedName!p
...

resolves to Context.Properties instead of 
dcompute.driver.ocl.context.Context.Properties, thus avoiding 
many template instantiations.


 Alas typeof(p).stringof, which yields Properties, errors "No 
such identifier Properties" (and subsequently crashes the CTFE 
engine).


I tried looking at the fullyQualifiedName but got lost pretty 
quick.


If I understand things correctly, you only care about enums 
nested in scopes up to the module scope, right? If so, this seems 
to fit the bill:


enum A {a}

struct S {
enum B {b}
struct S2 {
enum C {c}
C c;
}
A a;
B b;
int n, m;
pragma(msg, partiallyQualifiedName!n); // S.n
pragma(msg, partiallyQualifiedName!(S2)); // S.S2
pragma(msg, partiallyQualifiedName!(typeof(a))); // A
pragma(msg, partiallyQualifiedName!(typeof(b))); // S.B
pragma(msg, partiallyQualifiedName!(typeof(S2.c))); // S.S2.C
pragma(msg, partiallyQualifiedName!(a)); // S.a
pragma(msg, partiallyQualifiedName!(b)); // S.b
pragma(msg, partiallyQualifiedName!(S2.c)); // S.S2.c
}

template isModule(alias a) {
static if (is(a) || is(typeof(a)) || a.stringof.length < 7) {
enum isModule = false;
} else {
enum isModule = a.stringof[0..7] == "module ";
}
}

template partiallyQualifiedName(alias a) {
static if (isModule!a) {
enum partiallyQualifiedName = "";
} else {
static if (!isModule!(__traits(parent, a))) {
enum prefix = 
partiallyQualifiedName!(__traits(parent, a)) ~ ".";

} else {
enum prefix = "";
}
enum partiallyQualifiedName = prefix ~ 
__traits(identifier, a);

}
}

Note that it fails for built-in types, arrays, and many other 
cases, and does not support const/immutable/shared/etc. It should 
cover the cases described, though, and that's what's most 
important. If more support is needed, consider it a starting 
point, and feel free to ask for more. :)


--
  Biotronic


Re: what operator(s) should I overload to prevent this?

2017-10-16 Thread Biotronic via Digitalmars-d-learn

On Monday, 16 October 2017 at 12:00:13 UTC, drug wrote:
I refactored `MyStructure` added own implementation of malloced 
array based on pureRealloc/pureFree instead of dynamic array I 
used before and now I have error:
Error: cannot implicitly convert expression get(msg.getData()) 
of type const(MyStructure) to MyStructure.


What operators should I overload to let this conversion? I've 
tryed opCast and it fails in other call sites, also I've tried 
opAssign - it didn't works, what worked is wrapping in ctor - 
MyStruct(const_var). But using ctor is not convenient.


The reason this doesn't work is you have some sort of 
non-immutable pointer, reference or array in your struct. I'm not 
sure why this worked before, since I have no idea what your code 
looks like. Hence, I can only give limited advice. Notably, the 
reasons this gives you a warning is because it would be unsafe to 
do a simple cast.


You might have turned immutable(T)[] into T[] (where T is int, 
byte, char, what-have-you). If this is the case, consider why 
this happened, and try to turn it back into immutable(T)[]. The 
same goes for immutable(T)*. Remember that an alias can make 
something immutable, so it might not be immediately obvious.


If you're fine with being unsafe, and can't find a solution like 
the above, consider this:


struct MyStruct {
MyStruct getUnsafe() const {
return cast(MyStruct)this;
}
alias getUnsafe this;
}

--
  Biotronic


Re: Temporary objects as function parameters or when-is-this-shit-going-to-end?

2017-10-13 Thread Biotronic via Digitalmars-d-learn

On Friday, 13 October 2017 at 10:35:56 UTC, Jack Applegame wrote:
Compiler creates struct on the stack and silently (without 
postblitting and destruction old object) moves it to another 
address. Is it normal? I don't think so.


It is. Structs have no identity, and the compiler/GC/whatever is 
free to copy and/or move them about as it sees fit (as long as 
there is ostensibly only one - no duplicate 
constructor/destructor calls, no desynching of state). That's why 
the documentation[1] says not to have internal pointers in 
structs.


WAT??? Compiler creates struct on the stack copies it without 
postblitting and destructs both objects.


Now this looks like a real bug. There should be a this(this) call 
in there.


Can I donate to the D Foundation and that my donations would be 
aimed at fixing exactly these bugs?


BountySource[2] lets you do basically exactly that.

[1]: https://dlang.org/spec/garbage.html, "Do not have pointers 
in a struct instance that point back to the same instance."


[2]: https://www.bountysource.com/


Re: For fun: Expressive C++ 17 Coding Challenge in D

2017-10-05 Thread Biotronic via Digitalmars-d-learn
On Wednesday, 4 October 2017 at 19:20:12 UTC, Jesse Phillips 
wrote:

On Wednesday, 4 October 2017 at 15:26:02 UTC, Ali Çehreli wrote:

On 10/04/2017 02:04 AM, Biotronic wrote:

...

Hey where is the list of features used e.g: ranges, ufcs...


Features used: D.

But sure, added them to the gist:
https://gist.github.com/Biotronic/0bc6048b880d67bfdca970453cc47cf9

Also added some more stuff to show off more D features, like 
unittests and @safe.


--
  Biotronic


Re: For fun: Expressive C++ 17 Coding Challenge in D

2017-10-04 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 4 October 2017 at 09:04:58 UTC, Biotronic wrote:
Since the code uses ranges though, a simple replacement of 
readText with an mmapped equivalent should enable humongous 
file support with no other code change required.


Drop-in replacement for readText:

struct MmText {
import std.mmfile;

ulong  _fileOffset;
MmFile _file;

this(string filename) {
_file = new MmFile(filename);
}

dchar front() {
auto end = min(_file.length, _fileOffset+4);
auto data = cast(string)_file[_fileOffset..end];
return decodeFront(data);
}

void popFront() {
auto end = min(_file.length, _fileOffset+4);
auto data = cast(string)_file[_fileOffset..end];
size_t bytes;
decodeFront(data, bytes);
_fileOffset += bytes;
}

bool empty() {
return _fileOffset >= _file.length;
}
}

--
  Biotronic


Re: How to implement `isTemplate` traits?

2017-10-04 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 4 October 2017 at 09:32:31 UTC, drug wrote:

I need to separate templates:
```
foreach(member; __traits(allMembers, V))
{
	static if (__traits(compiles, { auto _val = 
&__traits(getMember, value, member); })

{
		// a template needs to be instantiated to be addressable, so 
it works, but I think it's dirty hack instead of dry and clean 
way...

}
}
```
May be phobos has such traits somewhere?


template isTemplate(T...) if (T.length == 1) {
enum isTemplate = __traits(isTemplate, T[0]);
}

--
  Biotronic


Re: For fun: Expressive C++ 17 Coding Challenge in D

2017-10-04 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 3 October 2017 at 19:25:56 UTC, Ali Çehreli wrote:

Found on Reddit:


https://www.reddit.com/r/programming/comments/740617/the_expressive_c17_coding_challenge/

How would you do it in D?

Ali

P.S. You can ignore the following note from the challenge text; 
I don't think it applies to D. Honestly, I don't think it 
matters for C++17 either. :)


  "You can assume input files won't be super large and can fit 
fully into memory."


https://gist.github.com/Biotronic/0bc6048b880d67bfdca970453cc47cf9

I opted for writing to stdout instead, because 1) it's easier, x) 
it's less code, and b) it's more flexible.


The memory limitations certainly do apply - readText would fail 
upon reading humongous files, and for 32-bit programs the 
resulting string wouldn't be able to hold enough data. Since the 
code uses ranges though, a simple replacement of readText with an 
mmapped equivalent should enable humongous file support with no 
other code change required.


--
  Biotronic


Re: Struct bug?

2017-10-02 Thread Biotronic via Digitalmars-d-learn

On Monday, 2 October 2017 at 09:34:29 UTC, Andrea Fontana wrote:

Anyway: you cant put a default destructor on struct


True. In which case you should either @disable this() (which 
presents its own set of issues) or hide b behind a @property 
function, something like:


struct S {
B _b;

@property
B b() {
if (_b is null) _b = new B();
return b;
}
}

This exact same issue also crops up for classes, since 
typeid(T).initializer is simply blitted over the newly allocated 
memory. At least for classes we could change the language such 
that:


class C {
int[] p = new int[5];
}

is sugar for:

class C {
int[] p;
this() {
p = new int[5];
}
}

No such solution exists for structs, since they don't have 
default constructors.


--
  Biotronic


Re: Struct bug?

2017-10-02 Thread Biotronic via Digitalmars-d-learn

On Monday, 2 October 2017 at 08:47:47 UTC, Andrea Fontana wrote:

Why this code doesn't write two identical lines?

https://dpaste.dzfl.pl/e99aad315a2a

Andrea


A reduced example of where it goes wrong:

class B {}

struct A {
B b = new B;
}

unittest {
A a1, a2;
assert(a1 == a2);
}

In other words, when you initialize the class reference in your 
struct, it has to be a value that's known at compile-time. So the 
compiler creates a single instance of B, and every instance of A 
points to it. So this line:


A a = A(A(1), 2);

first appends 1 to b.data, then appends 2 to b.data, and it's the 
same b in both cases.


Not knowing what you're attempting to do, I'm not sure how to fix 
your problem. But if what I've described above does indeed cover 
it, initializing b in the constructor is the way to get it to 
work.


--
  Biotronic


Re: Is it possible to avoid call to destructor for structs?

2017-09-24 Thread Biotronic via Digitalmars-d-learn

On Sunday, 24 September 2017 at 18:46:15 UTC, Haridas wrote:
Also consider the following code. Please let me know if I am 
doing the right thing for dynamic arrays. My hack seems to have 
the desired effect on shutting down the destructor. Is this 
hack legal use of D? Can you please guide me if/how it can be 
achieved for std.container.Array?


// 
import std.stdio;

struct Bar {
  ~this() {
writeln("~Bar");
  }
}

void main() {
  { // dynamic array
Bar[] bars;
bars.length = 4;
void* tmp = bars.ptr;
delete(tmp);
bars.length = 0;
  }
  { // std.container.Array
import std.container: Array;
Array!Bar bars;
bars.length = 6;
// does not seem to work
void* tmp = &(bars[0]);
delete(tmp);
bars.length = 0;
  }
}


Since you're deleting the memory the dynamic array is pointing 
to, what you're doing is potentially unsafe - if anyone touches 
that memory after it's been deleted, nasal demons may follow.


What you want is something like this:

import std.stdio;

struct Bar
{
this(int n) {}

~this()
{
writeln("~Bar");
}
}

struct SuppressGC(T)
{
// Disguise T as a humble array.
private ubyte[T.sizeof] _payload;

// Create from instance of T.
this(T arg) {
_payload = *cast(ubyte[T.sizeof]*)
}

// Or forward constructor arguments to T's constructor.
static if (__traits(hasMember, T, "__ctor"))
{
this(Args...)(Args args)
if (__traits(compiles, (Args e){__traits(getMember, 
T.init, "__ctor")(e);}))

{
__traits(getMember, get, "__ctor")(args);
}
}

// Pretend to be a T.
@property
ref T get()
{
return *cast(T*)_payload.ptr;
}

alias get this;
}

void useBar(ref Bar b) {}

unittest
{
// Construct from instance.
//This creates a temporary on the stack, and its destructor 
will be called.

SuppressGC!Bar a = Bar(3);

// Or by forwarding constructor arguments.
// This constructs in-place inside SuppressGC, and no 
destructor will be called.

auto b = SuppressGC!Bar(3);

SuppressGC!Bar[] arr;
arr.length = 3;

// Another stack temporary. Destructor will be called.
arr[0] = Bar(5);

// No temp
arr[1] = SuppressGC!Bar(5);

// It even pretends to be the wrapped struct:
useBar(b);
}

In general, of course, this is a bad idea - there's probably a 
reason that destructor does the thing it's doing. If you're sure 
skipping it is what you want, go ahead.


--
  Biotronic


Re: Adding empty static this() causes exception

2017-09-13 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 12 September 2017 at 19:59:52 UTC, Joseph wrote:
The compiler shouldn't arbitrarily force one to make arbitrary 
decisions that waste time and money.


Like having a type system? Having to do *cast(int*) to 
interpret a string as an int isn't strictly necessary, and wastes 
dev time when they have to type extra letters.


Throwing an exception when there are import cycles that may cause 
problems is absolutely the correct thing to do. It's a choice 
between hard-to-figure-out errors that may depend on the order in 
which files were passed to the linker, and getting an exception 
before you've even started running your tests. If we could get 
this message at compile-time, that would of course be better, but 
that cannot be done in the general case due to separate 
compilation. If you want such a message in the cases where it is 
possible, feel free to create a pull request.


It would be possible to add a way to say 'ignore cycles for this 
module ctor', but as has been pointed out, cycles are generally a 
symptom of poor architecture, are brittle, and can almost always 
be avoided (and when they can't, there's a way around that too).


--
  Biotronic


Re: Adding empty static this() causes exception

2017-09-12 Thread Biotronic via Digitalmars-d-learn

The simplest example of a cycle is probably this:

module A;
import B;

int n1 = 17;
static this() {
n1 = n2;
}

//
module B;
import A;

int n2 = 42;
static this() {
n2 = n1;
}

What's the value of n1 and n2 after module constructors are run? 
Since both module constructors can run arbitrary code, it's 
impossible to prove in the general case whether one of them 
depends on the other.


--
  Biotronic


Re: Adding empty static this() causes exception

2017-09-12 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 12 September 2017 at 09:11:20 UTC, Joseph wrote:
I have two nearly duplicate files I added a static this() to 
initialize some static members of an interface.


On one file when I add an empty static this() it crashes while 
the other one does not.


The exception that happens is
Cyclic dependency between module A and B.

Why does this occur on an empty static this? Is it being ran 
twice or something? Anyway to fix this?


Seriously, simply adding static this() { } to module B crashes 
the program ;/ module A and module B both import each other 
because there are types that they need to share but that is 
all(one uses an enum of the other and vice versa).


https://dlang.org/spec/module.html#order_of_static_ctor

"Cycles (circular dependencies) in the import declarations are 
allowed as long as not both of the modules contain static 
constructors or static destructors. Violation of this rule will 
result in a runtime exception."


So if you have a static this() in both A and B, and A imports B 
and B imports A, you will get this error message. You can pass 
--DRT-oncycle=ignore to the program to hide the problem, but a 
better solution is to find a way to live with fewer static 
this()s.


The reason this exception is thrown is that one module's static 
this() might otherwise depend on another module's static this 
that depends on the first module again, and there is no good way 
to check if it actually depends or just potentially.


--
  Biotronic


Re: Anonymous nogc class

2017-09-08 Thread Biotronic via Digitalmars-d-learn

On Friday, 8 September 2017 at 12:32:35 UTC, Jiyan wrote:

On Friday, 8 September 2017 at 06:37:54 UTC, Biotronic wrote:

On Thursday, 7 September 2017 at 23:40:11 UTC, Jiyan wrote:

[...]


Sadly, even std.typecons.scoped isn't currently @nogc:
https://issues.dlang.org/show_bug.cgi?id=13972
https://issues.dlang.org/show_bug.cgi?id=17592

[...]


First thanks :)

i understand the part with scopedAnon, but can you explain what 
the ~this is referring to?

Is it the Modul destructor?


It's scoped!T's destructor. If you decide to use that workaround, 
you should probably copy scoped!T from std.typecons and have your 
own version. It's not safe in all cases, and the next standard 
library update might break it.


And in general is it just that scoped is just not marked @nogc 
or is it that it would really need to use the gc?


In your case, scoped!T is can be safely called from @nogc code, 
and thus could be marked @nogc. However, when a class C has a 
destructor that allocates, scoped!C could not be @nogc. So in 
order to be safe in all cases, it can't be @nogc in the general 
case.


--
  Biotronic


Re: Anonymous nogc class

2017-09-08 Thread Biotronic via Digitalmars-d-learn

On Thursday, 7 September 2017 at 23:40:11 UTC, Jiyan wrote:

Hey,
wanted to know whether it is possible to make anonymous nogc 
classes:


interface I
{
public void ap();
}
void exec(I i)
{
i.ap;
}

// now execute, but with something like `scope`
exec( new  class  I
{
int tr = 43;
override void ap(){tr.writeln;}
});

Thanks :)


Sadly, even std.typecons.scoped isn't currently @nogc:
https://issues.dlang.org/show_bug.cgi?id=13972
https://issues.dlang.org/show_bug.cgi?id=17592

This can be worked around by casting scoped's destructor to be 
@nogc, but that's a heavy-handed approach that ruins type safety, 
and is the wrong solution in non-@nogc situations. Should you 
want to, this is what it should look like:


~this()
{
(cast(void delegate(T) @nogc)((T t){
// `destroy` will also write .init but we have no 
functions in druntime
// for deterministic finalization and memory 
releasing for now.

.destroy(t);
}))(Scoped_payload);
}

If and when this issue is resolved, this should work:

interface I {
public void ap();
}

void exec(I i) {
i.ap;
}

auto scopedAnon(T)(lazy T dummy) if (is(T == class)) {
import std.typecons;
return scoped!T();
}

unittest {
auto i = scopedAnon(new class I {
int tr = 43;
override void ap() {
import std.stdio;
tr.writeln;
}
});
exec(i);
}

--
  Biotronic


Re: New programming paradigm

2017-09-07 Thread Biotronic via Digitalmars-d-learn
On Thursday, 7 September 2017 at 16:55:02 UTC, EntangledQuanta 
wrote:
Sorry, I think you missed the point completely... or I didn't 
explain things very well.


I don't think I did - your new explanation didn't change my 
understanding at least. This indicates I'm the one who's bad at 
explaining. Ah well.


The point of my post was mostly to rewrite the code you'd posted 
in a form that I (and, I hope, others) found easier to understand.



I see no where in your code where you have a variant like type.


True. I've now rewritten it to use std.variant.Algebraic with 
these semantics:


auto foo(T1, T2)(T1 a, T2 b, int n) {
import std.conv;
return T1.stringof~": "~to!string(a)~" - "~T2.stringof~": 
"~to!string(b);

}

unittest {
import std.variant;
Algebraic!(float, int) a = 4f;
Algebraic!(double, byte) b = 1.23;

auto res = varCall!foo(a, b, 3);
assert(res == "float: 4 - double: 1.23");
}

template varCall(alias fn) {
import std.variant;
auto varCall(int n = 0, Args...)(Args args) {
static if (n == Args.length) {
return fn(args);
} else {
auto arg = args[n];
static if (is(typeof(arg) == VariantN!U, U...)) {
foreach (T; arg.AllowedTypes) {
if (arg.type == typeid(T))
return varCall!(n+1)(args[0..n], 
arg.get!T, args[n+1..$]);

}
assert(false);
} else {
return varCall!(n+1)(args);
}
}
}
}

Sadly, by using std.variant, I've given up on the elegant 
switch/case in exchange for a linear search by typeid. This can 
be fixed, but requires changes in std.variant.


Of course, it would be possible to hide all this behind compiler 
magic. Is that desirable? I frankly do not think so. We should be 
wary of adding too much magic to the compiler - it complicates 
the language and its implementation. This is little more than an 
optimization, and while a compiler solution would be less 
intrusive and perhaps more elegant, I do not feel it provides 
enough added value to warrant its inclusion.


Next, I'm curious about this code:


void bar(var t)
{
writeln("\tbar: Type = ", t.type, ", Value = ", t);
}

void main()
{
   bar(3); // calls bar as if bar was `void bar(int)`
   bar(3.4f); // calls bar as if bar was `void bar(float)`
   bar("sad"); // calls bar as if bar was `void bar(string)`
}


What does 'var' add here, that regular templates do not? (serious 
question, I'm not trying to shoot down your idea, only to better 
understand it) One possible problem with var here (if I 
understand it correctly) would be separate compilation - a 
generated switch would need to know about types in other source 
files that may not be available at the time it is compiled.


Next:


var foo(var x)
{
   if (x == 3)
   return x;
   return "error!";
}


This looks like a sort of reverse alias this, which I've argued 
for on many occasions. Currently, it is impossible to implement a 
type var as in that function - the conversion from string to var 
would fail. A means of implementing this has been discussed since 
at least 2007, and I wrote a DIP[1] about it way back in 2013. It 
would make working with variants and many other types much more 
pleasant.


[1]: https://wiki.dlang.org/DIP52


Re: New programming paradigm

2017-09-07 Thread Biotronic via Digitalmars-d-learn
On Wednesday, 6 September 2017 at 23:20:41 UTC, EntangledQuanta 
wrote:
So, no body thinks this is a useful idea or is it that no one 
understands what I'm talking about?


Frankly, you'd written a lot of fairly dense code, so 
understanding exactly what it was doing took a while. So I sat 
down and rewrote it in what I'd consider more idiomatic D, partly 
to better understand what it was doing, partly to facilitate 
discussion of your ideas.


The usage section of your code boils down to this:

alias EnumA = TypeMap!(float, int);
alias EnumB = TypeMap!(double, byte);

auto foo(T1, T2)(T1 a, T2 b) {
import std.conv;
	return T1.stringof~": "~to!string(a)~" - "~T2.stringof~": 
"~to!string(b);

}

unittest {
int a = 4;
double b = 1.23;
EnumA enumAVal = EnumA.get!float;
EnumB enumBVal = EnumB.get!byte;

auto res = enumMapper!(foo, enumAVal, enumBVal)(a, b);
assert(res == "float: 4 - byte: 1");
}

With this implementation behind the scenes:

struct TypeMap(T...) {
import std.meta : staticIndexOf;

private int value;
alias value this;

alias Types = T;

static TypeMap get(T2)() if (staticIndexOf!(T2, T) > -1) {
return TypeMap(staticIndexOf!(T2, T));
}
}

template enumMapper(alias fn, Maps...) {
auto enumMapper(Args...)(Args args) {
return enumMapperImpl!(OpaqueAliasSeq!(), Args)(args);
}
auto enumMapperImpl(alias ArgTypes, Args...)(Args args) {
alias Assigned = ArgTypes.Aliases;
alias Remaining = Maps[Assigned.length..$];

static if (Remaining.length == 0) {
import std.traits : Parameters;
alias fun = fn!Assigned;
alias params = Parameters!fun;
return fun(castTuple!params(args).expand);
} else {
alias typemap = Remaining[0];
switch (typemap) {
foreach (T; typemap.Types) {
case typemap.get!T:
alias Types = OpaqueAliasSeq!(Assigned, 
T);

return enumMapperImpl!Types(args);
}
default: assert(false);
}
}
}
}

template castTuple(T...) {
import std.typecons : tuple;
auto castTuple(Args...)(Args args) if (Args.length == 
T.length) {

static if (T.length == 0) {
return tuple();
} else {
auto result = .castTuple!(T[1..$])(args[1..$]);
return tuple(cast(T[0])args[0], result.expand);
}
}
}

template OpaqueAliasSeq(T...) {
alias Aliases = T;
}


Re: Template substitution for function parameters

2017-09-03 Thread Biotronic via Digitalmars-d-learn
On Saturday, 2 September 2017 at 01:41:14 UTC, Nicholas Wilson 
wrote:

On Friday, 1 September 2017 at 11:33:15 UTC, Biotronic wrote:
On Friday, 1 September 2017 at 10:15:09 UTC, Nicholas Wilson 
wrote:

So I have the following types

struct DevicePointer(T) { T* ptr; }

struct Buffer(T)
{
void* driverObject;
T[] hostMemory;
}

and a function

auto enqueue(alias k)(HostArgsOf!k) { ... }

where k would be a function like

void foo( DevicePointer!float a, float b , int c) { ... }

How can I write HostArgsOf such that HostArgsOf!foo yields:
AliasSeq!(Buffer!float, float, int)
preferably in such a way that I can add additional 
transformations to it later on?


i.e. it substitutes the template DevicePointer for the 
template Buffer in Parameters!foo,
The templates can be assumed to not be nested templates, i.e. 
DevicePointer!(DevicePointer!(float)) will never occur 
neither will Buffer!(Buffer!(float) or any cross templates)


template k(alias fn) {
import std.meta, std.traits;
alias k = staticMap!(ReplaceTemplate!(DevicePointer, 
Buffer), Parameters!fn);

}

template ReplaceTemplate(alias needle, alias replacement) {
template ReplaceTemplate(alias T) {
static if (is(T : needle!Args, Args...)) {
alias ReplaceTemplate = replacement!Args;
} else {
alias ReplaceTemplate = T;
}
}
}


Hmm, it seems I oversimplified the example a bit and this 
doesn't quite work for my actual usecase.


struct DevicePointer(int n,T) { T* ptr; }

alias GlobalPointer(T) = DevicePointer!(1,T);

k!foo yields
DevicePointer!(cast(AddrSpace)1u, float), float, int
instead of
Buffer!float, float, int

I think because the is(T : needle!Args, Args...) fails.


It really shouldn't work at all - the is(T : ...) works great, 
but gives Args as (1, float), and fails to instantiate Buffer 
with those arguments. This should give a compilation error.


Anyways, updated code that should work:

template ReplaceTemplate(alias needle, alias replacement) {
template ReplaceTemplate(alias T) {
static if (is(T : needle!Args, Args...)) {
alias ReplaceTemplate = replacement!(Args[1]);
} else {
alias ReplaceTemplate = T;
}
}
}

If you only ever use this for DevicePointer and Buffer, a less 
generic solution might be more understandable for maintainers:


template ReplaceDevicePointer(alias T) {
static if (is(T : DevicePointer!(n, T), int n, T)) {
alias ReplaceDevicePointer = Buffer!T;
} else {
alias ReplaceDevicePointer = T;
}
}

--
  Biotronic


Re: 24-bit int

2017-09-02 Thread Biotronic via Digitalmars-d-learn
On Saturday, 2 September 2017 at 00:43:00 UTC, Nicholas Wilson 
wrote:

On Friday, 1 September 2017 at 22:10:43 UTC, Biotronic wrote:

struct int24 {
ubyte[3] _payload;

this(int x) {
value = x;
}

...
}


You may also want to put an align(1) on it so that you dont 
waste 25% of the allocated memory in an array of int24's


The very first test in my code checks this:

int24[3] a;
assert(a.sizeof == 9);

On the other hand, using Mir's well-tested code instead of 
something I hacked together in 10 minutes is probably a good idea.


--
  Biotronic


Re: get parameter names

2017-09-01 Thread Biotronic via Digitalmars-d-learn
On Friday, 1 September 2017 at 20:58:20 UTC, EntangledQuanta 
wrote:


template(A, B...)
{
   auto foo(C...)(C c)
   {
   ... get c's parameter names, should be alpha, beta
   }
}


foo!(., .)(alpha, beta)

I need the actual identifiers passed to foo. I can get the 
types(obviously C) but when I try to get the identifier 
names(__traits(identifier or other methods) I stuff get 
_param_k or errors.


I need both C's types and the parameter identifier names past, 
else I'd just pass as strings.


Like Jonathan M Davis points out, this is impossible for regular 
parameters. For template alias parameters, on the other hand, 
this works:


void bar(alias fn)() {
assert(fn.stringof == "alpha");
}

unittest {
int alpha;
bar!(alpha);
}

--
  Biotronic


Re: 24-bit int

2017-09-01 Thread Biotronic via Digitalmars-d-learn
On Friday, 1 September 2017 at 19:39:14 UTC, EntangledQuanta 
wrote:
Is there a way to create a 24-bit int? One that for all 
practical purposes acts as such? This is for 24-bit stuff like 
audio. It would respect endianness, allow for arrays int24[] 
that work properly, etc.


I haven't looked at endianness beyond it working on my computer. 
If you have special needs in that regard, consider this a 
starting point:



struct int24 {
ubyte[3] _payload;

this(int x) {
value = x;
}

@property
int value() {
int val = *cast(int*)&_payload & 0xFF;

if (val & 0x80) {
val |= 0xFF00;
}

return val;
}

@property
int value(int x) {
_payload = (cast(ubyte*))[0..3];
return value;
}

auto opUnary(string op)() {
static if (op == "++") {
value = value + 1;
} else static if (op == "--") {
value = value - 1;
} else static if (op == "+") {
return value;
} else static if (op == "-") {
return -value;
} else static if (op == "~") {
return ~value;
} else {
static assert(false, "Unary operator '"~op~"' is not 
supported by int24.");

}
}

auto opOpAssign(string op)(int x) {
static assert(__traits(compiles, {mixin("value = value 
"~op~" x;");}), "Binary operator '"~op~"' is not supported by 
int24.");


mixin("value = value "~op~" x;");
return this;
}

alias value this;
}

unittest {
int24[3] a;
assert(a.sizeof == 9);

// Max value
a[1] = 8388607;
assert(a[1] == 8388607);
// Test for buffer overflow:
assert(a[0] == 0);
assert(a[2] == 0);

// Overflow
a[1] = 8388608;
assert(a[1] == -8388608);
// Test for buffer overflow:
assert(a[0] == 0);
assert(a[2] == 0);

// negative value
a[1] = -1;
assert(a[1] == -1);
// Test for buffer overflow:
assert(a[0] == 0);
assert(a[2] == 0);

// Unary operators
a[1] = 0;
assert(~a[1] == -1);
a[1]--;
assert(a[1] == -1);
assert(-a[1] == 1);
assert(+a[1] == -1);
a[1]++;
assert(a[1] == 0);

// Binary operators
a[1] = 0;
a[1] = a[1] + 1;
assert(a[1] == 1);
a[1] += 1;
assert(a[1] == 2);
a[1] = a[1] - 1;
assert(a[1] == 1);
a[1] -= 1;
assert(a[1] == 0);

a[1] = 3;
a[1] = a[1] * 2;
assert(a[1] == 6);
a[1] = a[1] / 2;
assert(a[1] == 3);
a[1] *= 2;
assert(a[1] == 6);
a[1] /= 2;
assert(a[1] == 3);
a[1] = a[1] << 1;
assert(a[1] == 6);
a[1] <<= 1;
assert(a[1] == 12);
a[1] = a[1] >> 1;
assert(a[1] == 6);
a[1] >>= 1;
assert(a[1] == 3);

a[1] |= 4;
assert(a[1] == 7);
a[1] &= 5;
assert(a[1] == 5);
a[1] = a[1] | 2;
assert(a[1] == 7);
a[1] = a[1] & 3;
assert(a[1] == 3);
}

--
  Biotronic


Re: Template substitution for function parameters

2017-09-01 Thread Biotronic via Digitalmars-d-learn
On Friday, 1 September 2017 at 10:15:09 UTC, Nicholas Wilson 
wrote:

So I have the following types

struct DevicePointer(T) { T* ptr; }

struct Buffer(T)
{
void* driverObject;
T[] hostMemory;
}

and a function

auto enqueue(alias k)(HostArgsOf!k) { ... }

where k would be a function like

void foo( DevicePointer!float a, float b , int c) { ... }

How can I write HostArgsOf such that HostArgsOf!foo yields:
AliasSeq!(Buffer!float, float, int)
preferably in such a way that I can add additional 
transformations to it later on?


i.e. it substitutes the template DevicePointer for the template 
Buffer in Parameters!foo,
The templates can be assumed to not be nested templates, i.e. 
DevicePointer!(DevicePointer!(float)) will never occur neither 
will Buffer!(Buffer!(float) or any cross templates)


template k(alias fn) {
import std.meta, std.traits;
alias k = staticMap!(ReplaceTemplate!(DevicePointer, Buffer), 
Parameters!fn);

}

template ReplaceTemplate(alias needle, alias replacement) {
template ReplaceTemplate(alias T) {
static if (is(T : needle!Args, Args...)) {
alias ReplaceTemplate = replacement!Args;
} else {
alias ReplaceTemplate = T;
}
}
}


Re: Bug in D!!!

2017-09-01 Thread Biotronic via Digitalmars-d-learn
On Thursday, 31 August 2017 at 15:48:12 UTC, EntangledQuanta 
wrote:

On Thursday, 31 August 2017 at 10:34:14 UTC, Kagamin wrote:
On Thursday, 31 August 2017 at 00:49:22 UTC, EntangledQuanta 
wrote:

I've already implemented a half ass library solution.


It can be improved alot.


Then, by all means, genius!


Enjoy!

mixin template virtualTemplates(alias parent, alias fn, T...) {
import std.meta;
alias name = Alias!(__traits(identifier, fn)[1..$]);
mixin virtualTemplates!(parent, name, fn, T);
}

mixin template virtualTemplates(alias parent, string name, alias 
fn, T...) {

import std.traits;
static if (is(parent == interface)) {
template templateOverloads(string name : name) {
alias templateOverloads = T;
}
alias Types = T;
} else {
alias Types = templateOverloads!name;
}

mixin(virtualTemplatesImpl(name, Types.length, is(parent == 
class)));

}

string virtualTemplatesImpl(string name, int n, bool implement) {
import std.format;
string result;
foreach (i; 0..n) {
auto body = implement ? format(" { return 
fn!(Types[%s])(args); }", i) : ";";
result ~= format("ReturnType!(fn!(Types[%s])) 
%s(Parameters!(fn!(Types[%s])) args)%s\n", i, name, i, body);

}
return result;
}

interface I {
void _Go(T)(T s);
void _Leave(T)(T s);
mixin virtualTemplates!(I, _Go, int, short, float, double);
mixin virtualTemplates!(I, "Abscond", _Leave, int, short, 
float, double);

}

class C : I {
void _Go(T)(T s) { }
void _Leave(T)(T s) { }
mixin virtualTemplates!(C, _Go);
mixin virtualTemplates!(C, "Abscond", _Leave);
}

unittest {
I c = new C();

c.Go(3.2);
c.Abscond(3.4f);
}

Does not support multiple template parameters, or template value 
parameters. Use at own risk for any and all purposes.


Re: Missing array element

2017-08-30 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 30 August 2017 at 06:16:16 UTC, Vino.B wrote:

On Tuesday, 29 August 2017 at 18:39:03 UTC, Ali Çehreli wrote:

https://dlang.org/phobos/std_algorithm_setops.html#.setDifference



 I tried the setDifference but does seem to be working as 
expected


From the documentation of setDifference: "The two ranges are 
assumed to be sorted by less."


In other words, you will need to sort your ranges first. Either 
pre-sort them as


string[] a = ["test1", "test2", "test3", "test4"];
string[] b = ["test2", "test4"]';

or call setDifference(a.sort(), b.sort()).

--
  Biotronic


Re: If structures places data to stack why we do not getting stackoverflow on array of structures?

2017-08-16 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 16 August 2017 at 12:50:07 UTC, Suliman wrote:

MyStruct[] is actually a struct similar to this:

struct MyStruct[] {
MyStruct* ptr;
size_t length;
}

That struct is placed on the stack, but the data it points to, 
via the ptr field, is heap allocated.


What is struct? Just name and size?


I'm sorry, I don't understand what you're asking. Can you please 
repeat with more information?


--
  Biotronic


Re: If structures places data to stack why we do not getting stackoverflow on array of structures?

2017-08-16 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 16 August 2017 at 07:39:01 UTC, Suliman wrote:

On the heap, unless you are allocating it via e.g. alloca.


If
struct MyStruct
{
 int x;
 int y;
}

MyStruct mystruct;

is located on stack, why:

MyStruct [] mystructs;

should located on heap?


MyStruct[] is actually a struct similar to this:

struct MyStruct[] {
MyStruct* ptr;
size_t length;
}

That struct is placed on the stack, but the data it points to, 
via the ptr field, is heap allocated.


One explanation of why is that the compiler doesn't know how many 
elements are in the array, and that that number may change. If it 
was stack-allocated and a new element was added to the array, 
everything on the stack would have to be moved.


If the compiler does know the number of elements, it can allocate 
the array on the stack (theoretically, this could be done as an 
optimization, but in practice I don't think it is). You can give 
the compiler this information:


MyStruct[10] mystructs;

This will allocate 10 MyStructs (80 bytes) on the stack, and if 
you change 10 to a large number, will give a stack overflow.


--
  Biotronic


Re: Why does stringof not like functions with arguments?

2017-08-09 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 9 August 2017 at 01:39:07 UTC, Jason Brady wrote:

Why does the following code error out with:

app.d(12,10): Error: function app.FunctionWithArguments (uint 
i) is not callable using argument types ()


Like Olivier said, stringof expects a valid expression. There are 
a few other options:


module foo;
import std.traits;
pragma(msg, bar(3).stringof);   // prints "bar(3)"
pragma(msg, ().stringof);   // "& bar"
pragma(msg, fullyQualifiedName!bar);// "foo.bar"
pragma(msg, __traits(identifier, bar)); // "bar"
void bar(int n) {}


Re: Function with static array as parameter

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 12:20:11 UTC, Miguel L wrote:
What is the best way in D to create a function that receives a 
static array of any length?


You will need to use templates:

void foo(size_t N)(int[N] arr) {
}

--
  Biotronic


Re: Foreign threads in D code.

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 12:08:35 UTC, Jacob Carlborg wrote:

On 2017-07-12 11:28, Biotronic wrote:


That's basically what I tried to say


It wasn't very clear to me at least.


Yeah, I see it in retrospect. "might collect memory that the 
thread is referencing on the stack or in non-GC memory" doesn't 
convey that the collected memory is only that which is allocated 
by the GC.


--
  Biotronic


Re: Struct Constructor Lazy

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 12:02:37 UTC, Jiyan wrote:

Thank you, one last question:
If i declare the parameter as ref i, then there shouldnt be any 
overhead wouldnt it?


Thanks :)


That would be basically the exact equivalent - instead of passing 
an int, you'll be passing a pointer.


--
  Biotronic


Re: Struct Constructor Lazy

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 11:34:45 UTC, Jiyan wrote:

Hey,
yes i did but to be honest i used dmd in debug version.
The thing about the static one, is that it creates a local 
object A isnt that a performance issue itself - or am i wrong - 
im confused actually :P?


Debug = no optimization. Looking at the generated assembly in a 
debug build is worthless.


You raise a valid point. In a debug build, you're probably right 
- it will need to copy the temporary to the target. With 
optimizations enabled, NRVO[0] will populate the target directly, 
resulting in roughly the equivalent of this code:


struct A {
int field;
static void opCall(A* p) {
p.field = getDataFromFile("file.txt");
}
}

A a;
A();

If the function is inlined, the whole problem is of course moot. 
There are probably other optimizations that can interfere with 
what I've described.


--
  Biotronic

[0]: https://en.wikipedia.org/wiki/Return_value_optimization


Re: Struct Constructor Lazy

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 11:00:54 UTC, Jiyan wrote:

Hey there:)

i want to know whether the following is somehow possible:
structs dont have default constructors, i know so:

struct A
{
int field;
this(int i){field = getDataFromFile("file.txt");}
}

A instance = A(0);

Here comes my issue:
when A(0) is called I would want here optimal performance, so 
there doesnt even need to be a value pushed on the stack (i=0), 
what would be like having a constructor with zero arguments (i 
is never used!).

Im pretty new to D, can somebody tell me how i would do this?
Is this(lazy int i){ ... a solution?


The traditional solution is static opCall:

struct A {
int field;
static A opCall() {
A result;
result.field = getDataFromFile("file.txt");
return result;
}
}

A instance = A();

I believe I've heard this is frowned upon these days, but I don't 
know of a better solution.


For optimal speed you might also want to skip default 
initialization of result, by writing A result = void;.


I would be surprised if the optimizer wasn't able to optimize 
away the useless parameter though - have you looked at the 
generated assembly?


--
  Biotronic


Re: Foreign threads in D code.

2017-07-12 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 12 July 2017 at 09:10:07 UTC, Jacob Carlborg wrote:

On 2017-07-11 08:18, Biotronic wrote:

If DRuntime is not made aware of the thread's existence, the 
thread will not be stopped by the GC, and the GC might collect 
memory that the thread is referencing on the stack or in 
non-GC memory.


Are you sure? Wouldn't that make malloc or any other custom 
allocators completely useless and the D GC would completely 
break the C standard library because it could collect memory 
allocated by the C standard library?


From "How Garbage Collection Works":

"5. Freeing all **GC** allocated memory that has no active 
pointers to it and do not need destructors to run" [1]. I added 
the emphasize on "GC".


From "Interfacing Garbage Collected Objects With Foreign Code"

"If the only pointer to an object is held outside of these 
areas, then the collector will miss it and free the memory. To 
avoid this from happening, either
* reallocate and copy the object using the foreign code's 
storage allocator or using the C runtime library's 
malloc/free." [2].


[1] http://dlang.org/spec/garbage.html#how_gc_works
[2] http://dlang.org/spec/garbage.html#gc_foreign_obj


That's basically what I tried to say - the GC may collect memory 
*it has allocated* if the only pointers to it are in memory the 
GC doesn't scan (i.e. on the stack of an unregistered thread or 
in memory not allocated via the GC).


It will not collect memory allocated by other means, but that 
Foo* you got from D and are using in C++ might point to a Bar 
soon after the GC runs.


--
  Biotronic


Re: Foreign threads in D code.

2017-07-11 Thread Biotronic via Digitalmars-d-learn

On Monday, 10 July 2017 at 20:03:32 UTC, Igor Shirkalin wrote:

Hello!

I have written some D code that I need to link to :C++ huge 
project. Let it be just one function that uses GC. The question 
is: if C++ code creates several threads and runs this :D 
function simultaneously, will GC work correctly?


p.s. Of course the druntime is initialized before it.

Igor Shirkalin


If DRuntime is not made aware of the thread's existence, the 
thread will not be stopped by the GC, and the GC might collect 
memory that the thread is referencing on the stack or in non-GC 
memory. Anything allocated by the GC would still be scanned.


To inform DRuntime about your thread, you should call 
thread_attachThis:


https://dlang.org/phobos/core_thread.html#.thread_attachThis

As pointed out in the documentation of thread_attachThis, you 
might also want to call rt_moduleTlsCtor, to run thread local 
static constructors. Depending on your usage, this might not be 
necessary.


--
  Biotronic


Re: Implementing interfaces using alias this

2017-06-16 Thread Biotronic via Digitalmars-d-learn

On Thursday, 15 June 2017 at 18:49:58 UTC, Jesse Phillips wrote:

wrap!IDuck


Ah, so it does exist in Phobos. I thought it should be there, but 
didn't find it. Thanks!


--
  Biotronic


Re: Implementing interfaces using alias this

2017-06-15 Thread Biotronic via Digitalmars-d-learn
On Wednesday, 14 June 2017 at 09:34:27 UTC, Balagopal Komarath 
wrote:

void main()
{
Test!Duck d;
}


As has been pointed out at length by others here, it's simply not 
how alias this is intended to work. I do see some arguments in 
favor of working that way, but I'm not sure what's the right 
solution.


Anyways, there is another solution - we could write a template 
that does the conversion for us. There is std.typecons.Proxy, 
which seems like a good fit, however it doesn't work quite the 
way we want. Here however, is a solution that works for simple 
examples. It might work for more complex examples as well, but I 
simply haven't tested that:


template duckImpl(alias a, TI, Fns...) {
static if (Fns.length > 0) {
mixin duckImpl!(a, TI, Fns[1..$]);

alias thisFn = Fns[0];
enum string fnName = __traits(identifier, thisFn);

mixin("ReturnType!thisFn "~fnName~"(Parameters!thisFn 
args) { return a."~fnName~"(args); }");

}
}

template duck(TI) if (is(TI == interface)) {
TI duck(T)(T t) {
import std.meta;
import std.traits;

template Functions(string s) {
alias Functions = MemberFunctionsTuple!(TI, s);
}

static class Result : TI {
private T payload;
this(T value) {
payload = value;
}
mixin duckImpl!(payload, TI, staticMap!(Functions, 
__traits(allMembers, TI)));

}
return new Result(t);
}
}

interface I {
void bar();
}

struct S {
void bar() {
import std.stdio;
writeln("OHAI");
}
}

unittest {
I i = S().duck!I;
i.bar();
}

--
  Biotronic


Re: O(1) sum

2017-06-12 Thread Biotronic via Digitalmars-d-learn

On Monday, 12 June 2017 at 01:36:04 UTC, Stefan Koch wrote:

On Monday, 12 June 2017 at 01:02:58 UTC, helxi wrote:

Is it possible to sum an array in O(1)?


No.
If you want to sum the elements you have to at-least look at 
all the elements.

So it'll always be O(N).
it's the best you can do.


On a multi-core system we can do better:

auto nums = iota(10_000_000.0f);
auto sum = taskPool.reduce!"a + b"(nums);

Given arbitrary parallelism (yeah, right!), this will be 
O(log(N)). For real-world systems, it might give a speed-up for 
large arrays, but won't reduce the big-O complexity. Of course, 
there will also be overhead to such a solution, so there is a 
limit to how much one'd actually benefit from it.


--
  Biotronic


Re: import statement placement

2017-06-07 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 7 June 2017 at 12:39:07 UTC, Russel Winder wrote:
Are there any idiom rules as to where to put import statements 
in D?


In Python they can go anywhere but PEP-8 suggests they should 
all go at the top of a file, just after the module 
documentation string.


I don't know if there is any official dogma on how to use 
imports, but given that local imports inside templates are only 
loaded if the template is instantiated, there are benefits to 
using local imports in those cases.


Another use for local imports is in unittests - any import that 
is only used in unittests may benefit from being moved from 
module scope to inside the unittests themselves, or for an import 
used by many tests, a version (unittest) block.


In my own code, I use very loose guidelines but prefer to put any 
imports that are used only in one or two functions, inside those 
functions. Imports that are used by multiple functions are placed 
at the top of the file, just below the module declaration (if 
any).


Similarly, I try to use selective imports when only a few symbols 
from a module are used in my module, but find that this becomes 
unwieldy past 3-5 symbols.


--
  Biotronic


Re: Can assumeSafeAppend() grab more and more capacity?

2017-06-07 Thread Biotronic via Digitalmars-d-learn

On Wednesday, 7 June 2017 at 05:43:06 UTC, ag0aep6g wrote:

[snip]


It seems to me this is a topic worthy of a more in-depth article. 
If only I felt up to that. :p


When you create a slice 'a' in D (with the current GC and 
druntime, at least), what happens behind the scenes is the 
allocator chops off a block of N bytes, where N is some number 
larger than a.length*typeof(a[0]).sizeof. For an array of two 
ints, N is 16.
For good measure, let's make a copy 'b' of that slice (it will 
come in handy later):


int[] a = [1, 2];
int[] b = a;

import std.stdio;
writeln(a.capacity);

3

writeln(b.capacity);

3


The capacity is 3. Intriguing, as a block of 16 bytes should be 
able to hold 4 ints.


We can ask the GC for more info on this block:

import core.memory;
auto info = GC.query(a.ptr);
writefln("0x%x, %s, %s ", info.base, info.size, info.attr);

0x2211010, 16, 10


That's the pointer to the start of the block, the size of the 
block, and various attributes (appendable, e.g.).

We can get the raw data of the block:

auto block = (cast(ubyte*)info.base)[0..info.size];
writeln(block);

[1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]


We can see our 1 and 2 in there, and a curious 8 at the end. 
That's the currently used data, in bytes. That's also the reason 
the capacity is 3, not 4 - this info has to live somewhere. If we 
were to append another element, and print the data again:


a ~= 3;
writeln(block);

[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 12]


See how the last byte changed to a 12? That just so happens to be 
a.length*int.sizeof.


Remember how we made a copy of the slice above? The copy's 
capacity is now 0, while a's capacity is 3. The algorithm for 
capacity is actually pretty simple:


int capacity;
if (a.length*int.sizeof == block[$-1])
capacity = (block.length - 1) / int.sizeof;
else
capacity = 0;
writeln(capacity);

3


What happens when we call assumeSafeAppend?

b.assumeSafeAppend;
writeln(block);

[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 8]


Hey, the 'used' byte is 8 again. That means a.capacity is 0, 
while b.capacity is 3.


Now for a curious thing: what happens to a's capacity when we 
append to b?


b ~= 4;
writeln(a.capacity);

3


As above, the length of a in bytes equals the used bytes in the 
allocated memory block, and so both a and b have capacity again.


This has of course overwritten a[2], which used to be 3 and is 
now 4. assumeSafeAppend breaks part of D's type system for 
optimization purposes, and this is the result.


Note that the details in this post are only correct for small 
blocks (<=256 bytes). For larger blocks, the 'used' field is 
larger, but the algorithms and concepts are the same.


For the actual implementation of a.capacity, you can have a 
look-see at 
https://github.com/dlang/druntime/blob/master/src/rt/lifetime.d#L734, which is called from https://github.com/dlang/druntime/blob/master/src/object.d#L2968.


--
  Biotronic


Re: How to cleanup array of structs?

2017-06-02 Thread Biotronic via Digitalmars-d-learn

On Friday, 2 June 2017 at 13:32:02 UTC, Suliman wrote:
I remember that there was topic about remobing data from 
struct/arrays of structs. But I do not remember what is 
idiomatic way to do it, and can't google it.


something like:
struct MyTrack
{
ulong id;
string recordDate;
int velocity;
int maxAllowedSpeedForRoad;
}

MyTrack mytrack;
MyTrack [] mytracks;

// filling

mytracks.clean() or what?


There are multiple options

// Will set the array to an empty one, and leave the
// old one for the GC to clean up when it feels like it.
// The safest way.
mytracks = null;

// Mostly equivalent:
mytracks = [];

// Will reuse the array, overwriting existing data.
// If other parts of the program are using existing data
// in the array, this will lead to hard-to-track-down bugs.
mytracks.length = 0;
mytracks.assumeSafeAppend();

// If you just want to get rid of the last element you added to 
the array:

mytracks = mytracks[0..$-1];

--
  Biotronic


Re: purity question

2017-05-30 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 13:45:07 UTC, Rene Zwanenburg wrote:

On Tuesday, 30 May 2017 at 11:34:52 UTC, ketmar wrote:
If malloc were marked as pure, wouldn't that mean it must 
return the same pointer every time you call it with the same 
size?


of course. but D "pure" is not what other world knows as 
"pure". we love to mess with words.


Well, there's the ability to modify non-const reference 
parameters from a pure function, but that's not applicable to 
malloc. Are there any other special rules?


The rules[0] are:

0) Can't call functions not marked pure.
1) Can't touch anything mutable that's not explicitly passed to 
the pure function.
1b) Except GC internal state - i.e. memory can be allocated via 
the GC.

1c) And floating-point exception flags and modes.
2) Can't do I/O (can be seen as a special case of 1 and 0).

There's a few more details, but that's the important stuff.

For a good article on the subject, I recommend David Nadlinger's 
Purity in D:


http://klickverbot.at/blog/2012/05/purity-in-d/

[0]: https://dlang.org/spec/function.html#pure-functions


Re: Error: func(const(A) a) is not callable using argument types (const(A)

2017-05-30 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 10:46:12 UTC, Andrew Edwards wrote:

On Tuesday, 30 May 2017 at 10:37:58 UTC, Biotronic wrote:

On Tuesday, 30 May 2017 at 10:31:24 UTC, Daniel Kozak wrote:

import std.traits : fqn = fullyQualifiedName;


Darnit. I just googled the template and got a result talking 
about fqn!T. So yeah - this code:


import std.traits;

pragma(msg, fullyQualifiedName!ImVec2);
pragma(msg, fullyQualifiedName!(typeof(CalcTextSize(label.ptr, 
null, true;


--
  Biotronic


This is exactly the cause. Output is follows:

internal.ImVec2
types.ImVec2

I'm leveraging types as I try to do my own port of the lib so 
CalcTextSize is returning an instance of ImVec2 as defined 
types and I'm trying to assign to one I have declared in 
internal.


Thanks.


Pleasure. :)

I don't know why you have two different ImVec2s, but you may have 
good reasons to. If they need to be separate, you'll need to 
write a conversion function between the two for the cases where 
you have one and want the other. This could be the constructor or 
opAssign, or a standalone function if you want to be more 
explicit about it.


I'd argue that error message could be improved upon, btw.

--
  Simen


Re: Error: func(const(A) a) is not callable using argument types (const(A)

2017-05-30 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 10:31:24 UTC, Daniel Kozak wrote:

import std.traits : fqn = fullyQualifiedName;


Darnit. I just googled the template and got a result talking 
about fqn!T. So yeah - this code:


import std.traits;

pragma(msg, fullyQualifiedName!ImVec2);
pragma(msg, fullyQualifiedName!(typeof(CalcTextSize(label.ptr, 
null, true;


--
  Biotronic


Re: Error: func(const(A) a) is not callable using argument types (const(A)

2017-05-30 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 10:09:50 UTC, Andrew Edwards wrote:

What does that even mean?

Scenario:

bool func(const ImVec2 label_size)
{
return true;
}

void main()
{
//first attempt:
const ImVec2 label_size = CalcTextSize(label.ptr, null, 
true);
//Error: cannot implicitly convert expression 
(CalcTextSize(cast(immutable(char)*)label, null, true, -1F)) of 
type ImVec2 to const(ImVec2)


//second attempt
const ImVec2 label_size = 
cast(const)CalcTextSize(label.ptr, null, true);
// Error: cannot implicitly convert expression 
(CalcTextSize(cast(immutable(char)*)label, null, true, -1F)) of 
type const(ImVec2) to const(ImVec2)


//third attempt
const auto label_size = CalcTextSize(label.ptr, null, true);
//Okay: don't know why the other two didn't work but I can 
keep going for now


func(label_size);
//Error: function imgui_d.func (const(ImVec2) label_size) 
is not callable using argument types (const(ImVec2))

}


My immediate thought is 'is that the same ImVec2?' Do you have 
two definitions of ImVec2 laying about?


What's the output of this code, if you insert it somewhere in the 
above?


import std.traits;

pragma(msg, fqn!ImVec2);
pragma(msg, fqn!(typeof(CalcTextSize(label.ptr, null,

true;


--
  Biotronic


Re: Code improvement for DNA reverse complement?

2017-05-22 Thread Biotronic via Digitalmars-d-learn

On Monday, 22 May 2017 at 08:58:24 UTC, biocyberman wrote:
@Nicolas Wilson: Your explanation of the enum is clear and very 
helpful. I can recall to the same technique used in kh_hash in 
samtools and the associated. With that said, the chars enum is 
only to 'T' (85) elements.


The reason for having only 85 elements in the array was pure 
laziness - the problem description seems to forbid non-ACGT 
letters, so I saw no reason to write more code to handle them. :p 
My code will crash if the input string contains lower-case 
letters, Zs, or any other letter beyond 'T' (or read random bits 
of memory if you're lucky).



@ag0aep6g
You fell into a trap there. The value is calculated at compile 
time, but it has >copy/paste-like behavior. That is, whenever 
you use `chars`, the code behaves as if you >typed out the 
array literal. That means, the whole array is re-created on 
every iteration.


Use `static immutable` instead. It still forces compile-time 
calculation, but it doesn't > have copy/paste behavior. Speeds 
up revComp3 a lot.


With  'iteration' here you mean running lifetime of the 
function, or in other words, each one of the 10_000 cycles in 
the benchmark?


Could you provide some more reading for what you are telling 
here? I can only guess it is intrinsic behavior of an 'enum'.


ag0aep6g is absolutely correct in his observation, and the 
resulting code is basically this:


string revComp3(string bps) {
const N = bps.length;
static immutable chars_saved = [Repeat!('A'-'\0', '\0'), 'T',
Repeat!('C'-'A'-1, '\0'), 'G',
Repeat!('G'-'C'-1, '\0'), 'C',
Repeat!('T'-'G'-1, '\0'), 'A'];
char[] result = new char[N];
for (int i = 0; i < N; ++i) {
auto chars = chars_saved.dup; // Bad stuff happens here
result[i] = chars[bps[N-i-1]];
}
return result.assumeUnique;
}

As we can see, it copies the entire array for every character in 
the input string. That's basically an allocation and a memcpy in 
the innermost, hottest loop. Roughly as bad as it gets. (yup, 
that's 20 million allocations)


As for why this happens, enum can be thought of as the analog of 
C's #define - the compiler precalculates the data to fill the 
array, and then copies that into the source code every time it's 
used.


Re: Code improvement for DNA reverse complement?

2017-05-22 Thread Biotronic via Digitalmars-d-learn

On Friday, 19 May 2017 at 22:53:39 UTC, crimaniak wrote:

On Friday, 19 May 2017 at 12:55:05 UTC, Biotronic wrote:
revComp6 seems to be the fastest, but it's probably also the 
least readable (a common trade-off).

Try revComp7 with -release :)

string revComp7(string bps)
{
char[] result = new char[bps.length];
auto p1 = result.ptr;
auto p2 = [$ - 1];
enum AT = 'A'^'T';
enum CG = 'C'^'G';

while (p2 > bps.ptr)
{
   *p1 = *p2 ^ ((*p2 == 'A' || *p2 == 'T') ? AT : CG);
p1++;
p2--;
}
return result.assumeUnique;
}

In fact, when the size of the sequence is growing time 
difference between procedures is shrinking, so it's much more 
important to use memory-efficient presentation than to optimize 
logic.


revComp7 is pretty fast, but I followed ag0aep6g's advice:

On Friday, 19 May 2017 at 13:38:20 UTC, ag0aep6g wrote:
Use `static immutable` instead. It still forces compile-time 
calculation, but it doesn't have copy/paste behavior. Speeds up 
revComp3 a lot.


Also, with DMD (2.073.0) -release -O instead of -debug from this 
point. I'd blame someone else, but this is my fault. :p


Anyways, full collection of the various versions I've written, 
plus crimaniak's revComp7 (rebranded as revComp8, because I 
already had 7 at the time):


https://gist.github.com/Biotronic/20daaf0ed1262d313830bc8cd4199896

Timings:
revComp0:158 ms, 926 us
revComp1: 1 sec, 157 ms,  15 us
revComp2:604 ms,  37 us
revComp3: 18 ms, 545 us
revComp4: 92 ms, 293 us
revComp5: 86 ms, 731 us
revComp6: 94 ms,  56 us
revComp7:917 ms, 576 us
revComp8: 62 ms, 917 us

This actually matches my expectations - the table lookup version 
should be crazy fast, and it is. It beats even your revComp7 
(revComp8 in the table).


LDC (-release -O3) timings:

revComp0: 166 ms, 190 us
revComp1: 352 ms, 917 us
revComp2: 300 ms, 493 us
revComp3:  10 ms, 950 us
revComp4: 148 ms, 106 us
revComp5: 144 ms, 152 us
revComp6: 142 ms, 307 us
revComp7: 604 ms, 274 us
revComp8:  26 ms, 612 us

Interesting how revComp4-6 got slower. What I really wanted to 
see with this though, was the effect on revComp1, which uses 
ranges all the way.


Re: Code improvement for DNA reverse complement?

2017-05-19 Thread Biotronic via Digitalmars-d-learn

On Friday, 19 May 2017 at 12:21:10 UTC, biocyberman wrote:


1. Why do we need to use assumeUnique in 'revComp0' and 
'revComp3'?


D strings are immutable, so if I'd created the result array as a 
string, I couldn't change the individual characters. Instead, I 
create a mutable array, change the elements in it, then cast it 
to immutable when I'm done. assumeUnique does that casting while 
keeping other type information and arguably providing better 
documentation through its name. Behind the scenes, it's basically 
doing cast(string)result;


2. What is going on with the trick of making chars enum like 
that in 'revComp3'?


By marking a symbol enum, we tell the compiler that its value 
should be calculated at compile-time. It's a bit of an 
optimization (but probably doesn't matter at all, and should be 
done by the compiler anyway), and a way to say it's really, 
really const. :p


Mostly, it's a habit I try to build, of declaring symbols as 
const as possible, to make maintenance easier.



Bonus! Three more variations, all faster than revComp0:

string revComp4(string bps) {
const N = bps.length;
char[] result = new char[N];
for (int i = 0; i < N; ++i) {
switch(bps[N-i-1]) {
case 'A': result[i] = 'T'; break;
case 'C': result[i] = 'G'; break;
case 'G': result[i] = 'C'; break;
case 'T': result[i] = 'A'; break;
default: assert(false);
}
}
return result.assumeUnique;
}

string revComp5(string bps) {
const N = bps.length;
char[] result = new char[N];
foreach (i, ref e; result) {
switch(bps[N-i-1]) {
case 'A': e = 'T'; break;
case 'C': e = 'G'; break;
case 'G': e = 'C'; break;
case 'T': e = 'A'; break;
default: assert(false);
}
}
return result.assumeUnique;
}

string revComp6(string bps) {
char[] result = new char[bps.length];
auto p1 = result.ptr;
auto p2 = [$-1];

while (p2 > bps.ptr) {
switch(*p2) {
case 'A': *p1 = 'T'; break;
case 'C': *p1 = 'G'; break;
case 'G': *p1 = 'C'; break;
case 'T': *p1 = 'A'; break;
default: assert(false);
}
p1++; p2--;
}
return result.assumeUnique;
}

revComp6 seems to be the fastest, but it's probably also the 
least readable (a common trade-off).


Re: Code improvement for DNA reverse complement?

2017-05-19 Thread Biotronic via Digitalmars-d-learn

On Friday, 19 May 2017 at 07:29:44 UTC, biocyberman wrote:
I am solving this problem http://rosalind.info/problems/revc/ 
as an exercise to learn D. This is my solution:


https://dpaste.dzfl.pl/8aa667f962b7

Is there some D tricks I can use to make the 
`reverseComplement` function more concise and speedy? Any other 
comments for improvement of the whole solution are also much 
appreciated.


Question about your implementation: you assume the input may 
contain newlines, but don't handle any other non-ACGT characters. 
The problem definition states 'DNA string' and the sample dataset 
contains no non-ACGT chars. Is this an oversight my part or 
yours, or did you just decide to support more than the problem 
requires?



Here's a few variations I've come up with, and their timings on 
my machine:


import std.exception;
import std.stdio;
import std.conv;
import std.range;
import std.algorithm;
import std.datetime;
import std.meta;

string randomDna(int length) {
import std.random;
auto rnd = Random(unpredictableSeed);
enum chars = ['A','C','G','T'];
return iota(length).map!(a=>chars[uniform(0,4, rnd)]).array;
}

unittest {
auto input = randomDna(2000);

string previous = null;
foreach (fn; AliasSeq!(revComp0, revComp1, revComp2, 
revComp3)) {

auto timing = benchmark!({fn(input);})(10_000);
writeln(().stringof[2..$], ": ", 
timing[0].to!Duration);

auto current = fn(input);
if (previous != null) {
if (current != previous) {
writeln(().stringof[2..$], " did not give 
correct results.");

} else {
previous = current;
}
}
}
}

// 216 ms, 3 us, and 8 hnsecs
string revComp0(string bps) {
const N = bps.length;
char[] result = new char[N];
for (int i = 0; i < N; ++i) {
result[i] = {switch(bps[N-i-1]){
case 'A': return 'T';
case 'C': return 'G';
case 'G': return 'C';
case 'T': return 'A';
default: return '\0';
}}();
}
return result.assumeUnique;
}

// 2 secs, 752 ms, and 969 us
string revComp1(string bps) {
return bps.retro.map!((a){switch(a){
case 'A': return 'T';
case 'C': return 'G';
case 'G': return 'C';
case 'T': return 'A';
default: assert(false);
}}).array;
}

// 10 secs, 419 ms, 335 us, and 6 hnsecs
string revComp2(string bps) {
enum chars = ['A': 'T', 'T': 'A', 'C': 'G', 'G': 'C'];
auto result = appender!string;
foreach_reverse (c; bps) {
result.put(chars[c]);
}
return result.data;
}

// 1 sec, 972 ms, 915 us, and 9 hnsecs
string revComp3(string bps) {
const N = bps.length;
enum chars = [Repeat!('A'-'\0', '\0'), 'T',
Repeat!('C'-'A'-1, '\0'), 'G',
Repeat!('G'-'C'-1, '\0'), 'C',
Repeat!('T'-'G'-1, '\0'), 'A'];

char[] result = new char[N];
for (int i = 0; i < N; ++i) {
result[i] = chars[bps[N-i-1]];
}
return result.assumeUnique;
}


Re: What's a good wat to trunctate a time point

2017-05-10 Thread Biotronic via Digitalmars-d-learn

On Friday, 5 May 2017 at 09:14:21 UTC, Biotronic wrote:
Here's an implementation that supports start of year, month, 
week, day, hour, minute and second. Works for DateTime and 
SysTime. Not heavily tested (all tests included):


As the last sentence says, there were holes in the testing, 
specifically for unsupported units. Updated:


import std.datetime;

DateTime startOf(string unit, DayOfWeek start = 
DayOfWeek.sun)(DateTime dt) {

static if (unit == "year") {
return DateTime(dt.year, 1, 1);
} else static if (unit == "month") {
return DateTime(dt.year, dt.month, 1);
} else static if (unit == "week") {
auto delta = dt.dayOfWeek - start;
if (delta < 0) delta += 7;
return DateTime(dt.year, dt.month, dt.day) - 
dur!"days"(delta);

} else static if (unit == "day") {
return DateTime(dt.year, dt.month, dt.day);
} else static if (unit == "hour") {
return DateTime(dt.year, dt.month, dt.day, dt.hour);
} else static if (unit == "minute") {
return DateTime(dt.year, dt.month, dt.day, dt.hour, 
dt.minute);

} else static if (unit == "second") {
return DateTime(dt.year, dt.month, dt.day, dt.hour, 
dt.minute, dt.second);

} else {
static assert(false, "\"" ~ unit ~ "\" is not a valid 
time unit for startOf().\nPlease use one of \"year\", \"month\", 
\"week\", \"day\", \"hour\", \"minute\" or \"second\"");

}
}

SysTime startOf(string unit)(SysTime st) {
return SysTime(startOf!unit(cast(DateTime)st), st.timezone);
}

unittest {
auto now= DateTime(2017, 5,  5, 10, 39, 17);

auto expectedYear   = DateTime(2017, 1,  1,  0,  0,  0);
auto expectedMonth  = DateTime(2017, 5,  1,  0,  0,  0);
auto expectedWeek   = DateTime(2017, 4, 30,  0,  0,  0);
auto expectedDay= DateTime(2017, 5,  5,  0,  0,  0);
auto expectedHour   = DateTime(2017, 5,  5, 10,  0,  0);
auto expectedMinute = DateTime(2017, 5,  5, 10, 39,  0);
auto expectedSecond = DateTime(2017, 5,  5, 10, 39, 17);

auto startOfYear   = now.startOf!"year";
auto startOfMonth  = now.startOf!"month";
auto startOfWeek   = now.startOf!"week";
auto startOfDay= now.startOf!"day";
auto startOfHour   = now.startOf!"hour";
auto startOfMinute = now.startOf!"minute";
auto startOfSecond = now.startOf!"second";

assert(expectedYear   == startOfYear);
assert(expectedMonth  == startOfMonth);
assert(expectedWeek   == startOfWeek);
assert(expectedDay== startOfDay);
assert(expectedHour   == startOfHour);
assert(expectedMinute == startOfMinute);
assert(expectedSecond == startOfSecond);

now = DateTime(2017, 4, 30, 10, 39, 17);
auto expectedWeek2  = DateTime(2017, 4, 24,  0,  0,  0);
auto startOfWeek2   = now.startOf!("week", DayOfWeek.mon);
auto expectedWeek3  = DateTime(2017, 4, 29,  0,  0,  0);
auto startOfWeek3   = now.startOf!("week", DayOfWeek.sat);
auto expectedWeek4  = DateTime(2017, 4, 30,  0,  0,  0);
auto startOfWeek4   = now.startOf!("week", DayOfWeek.sun);

assert(startOfWeek2 == expectedWeek2);
assert(startOfWeek3 == expectedWeek3);
assert(startOfWeek4 == expectedWeek4);

assert(!__traits(compiles, now.startOf!"fortnight"));
}


Re: What's a good wat to trunctate a time point

2017-05-05 Thread Biotronic via Digitalmars-d-learn

On Friday, 5 May 2017 at 08:02:15 UTC, Dukc wrote:
I have a time point, be it SysTime or DateTime, whatever. I 
want to trunctate it to weeks, eg. I want it to become the 
first point of time during the week it was representing. What's 
a good way to do that? Only hacks came to my mind.


The solution does not have to be generic, trough I'd prefer it 
to be if it can be without much extra work.


Here's an implementation that supports start of year, month, 
week, day, hour, minute and second. Works for DateTime and 
SysTime. Not heavily tested (all tests included):


import std.datetime;

DateTime startOf(string unit, DayOfWeek start = 
DayOfWeek.sun)(DateTime dt) {

static if (unit == "year") {
return DateTime(dt.year, 1, 1);
} else static if (unit == "month") {
return DateTime(dt.year, dt.month, 1);
} else static if (unit == "week") {
auto delta = dt.dayOfWeek - start;
if (delta < 0) delta += 7;
return DateTime(dt.year, dt.month, dt.day) - 
dur!"days"(delta);

} else static if (unit == "day") {
return DateTime(dt.year, dt.month, dt.day);
} else static if (unit == "hour") {
return DateTime(dt.year, dt.month, dt.day, dt.hour);
} else static if (unit == "minute") {
return DateTime(dt.year, dt.month, dt.day, dt.hour, 
dt.minute);

} else static if (unit == "second") {
return DateTime(dt.year, dt.month, dt.day, dt.hour, 
dt.minute, dt.second);

}
}

SysTime startOf(string unit)(SysTime st) {
return SysTime(startOf!unit(cast(DateTime)st), st.timezone);
}

unittest {
auto now= DateTime(2017, 5,  5, 10, 39, 17);

auto expectedYear   = DateTime(2017, 1,  1,  0,  0,  0);
auto expectedMonth  = DateTime(2017, 5,  1,  0,  0,  0);
auto expectedWeek   = DateTime(2017, 4, 30,  0,  0,  0);
auto expectedDay= DateTime(2017, 5,  5,  0,  0,  0);
auto expectedHour   = DateTime(2017, 5,  5, 10,  0,  0);
auto expectedMinute = DateTime(2017, 5,  5, 10, 39,  0);
auto expectedSecond = DateTime(2017, 5,  5, 10, 39, 17);

auto startOfYear   = now.startOf!"year";
auto startOfMonth  = now.startOf!"month";
auto startOfWeek   = now.startOf!"week";
auto startOfDay= now.startOf!"day";
auto startOfHour   = now.startOf!"hour";
auto startOfMinute = now.startOf!"minute";
auto startOfSecond = now.startOf!"second";

assert(expectedYear   == startOfYear);
assert(expectedMonth  == startOfMonth);
assert(expectedWeek   == startOfWeek);
assert(expectedDay== startOfDay);
assert(expectedHour   == startOfHour);
assert(expectedMinute == startOfMinute);
assert(expectedSecond == startOfSecond);

now = DateTime(2017, 4, 30, 10, 39, 17);
auto expectedWeek2  = DateTime(2017, 4, 24,  0,  0,  0);
auto startOfWeek2   = now.startOf!("week", DayOfWeek.mon);
auto expectedWeek3  = DateTime(2017, 4, 29,  0,  0,  0);
auto startOfWeek3   = now.startOf!("week", DayOfWeek.sat);

assert(startOfWeek2 == expectedWeek2);
assert(startOfWeek3 == expectedWeek3);
}


Re: Multiple template alias parameters

2015-05-08 Thread Biotronic via Digitalmars-d-learn

On Friday, 8 May 2015 at 21:56:56 UTC, Brian Schott wrote:
Allowing template Tem(alias Args ...) syntax would let me 
trace multiple variables at once.


Actually, this already works:

void traceVars(alias T, U...)() {
import std.stdio : writeln;
writeln(T.stringof, : , T);
static if (U.length  0) {
traceVars!(U);
}
}

void main(string[] args) {
auto argslength = args.length;
auto args0 = args[0];

traceVars!(args, argslength, args0);
}

Sadly, the ... syntax precludes the use of __LINE__ and __FILE__. 
:(