Re: auto ref and arrays

2012-11-27 Thread Jack Applegame

http://d.puremagic.com/issues/show_bug.cgi?id=9090


safety of move

2012-11-27 Thread Ellery Newcomer

I find myself using [abusing?] move lately:

import std.algorithm;
import std.stdio;

struct A {
const(int) i;
int j;
int k;
}

void main() {
A* a = new A(); // pretend this is malloc or something
// *a = A(1)
A a2 = A(1);
move(a2, *a);

A[] arr = new A[](2);
//arr[1] = *a;
move(*a, arr[1]);
}

For the first part, I have a A* pointing to uninitialized memory and I 
need to initialize it somehow. move works I guess because it uses memcpy 
or something. Not complaining, but wondering.


The second part violates D's const semantics and maybe shouldn't be 
permitted. But it is.




Re: path matching problem

2012-11-27 Thread jerro

You could replace the inner loop with somehting like:

bool excl = exclude.any!(part => name.canFind(part));


std.algorithm seems to generally be running the match in the 
opposite direction, if I'm understanding it properly.  (Dealing 
with D template is always confusing to me.)  OTOH, I couldn't 
find the string any method, so I'm not really sure what you're 
proposing, though it does look attractive.


I don't understand what you mean with running the match in the 
opposite direction, but I'll explain how my line of code works. 
First of all, it is equivalent to:


any!(part => canFind(name, part))(exclude);

The feature that that lets you write that in the way I did in my 
previous post is called uniform function call syntax (often 
abbreviated to UFCS) and is described at 
http://www.drdobbs.com/cpp/uniform-function-call-syntax/232700394.


canFind(name, part) returns true if name contains part.

(part => canFind(name, part)) is a short syntax for (part){ 
return canFind(name, part); }


any!(condition)(range) returns true if condition is true for any 
element of range


So the line of code in my previous post sets excl to true if name 
contains any of the strings in exclude. If you know all the 
strings you want to exclude in advance, it is easier to do that 
with a regex like Joshua did.


If you want to learn about D templates, try this tutorial:

https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/dtemplates.pdf?raw=true

Still, though your basic approach sounds good, the suggestion 
of Joshua Niehus would let me filter out the strings that 
didn't fit before entering the loop.  There's probably no real 
advantage to doing it that way, but it does seem more elegant.


I agree, it is more elegant.



Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread jerro
won't. You seem to be looking for a function which will insert 
an element
between every element in a range rather than one that joins 
ranges, and I'm
not aware of any function in Phobos which will do that. There 
may be a way to
get one to do what you want, but I can't think of how at the 
moment.


roundRobin can be used for that. I think this is suposed to work:

auto r = roundRobin(arr, repeat(s).take(arr.length - 1));

This currently gives this error:

 Error: template instance 
std.range.roundRobin!(S[],Take!(Repeat!(S))) error instantiating


I think this is due to the fact that roundRobin.front has 
multiple return statements, some of which return an lvalue and 
some of which return an rvalue when instantiated with one range 
with rvalue elements and one with lvalue elements. The return 
type of roundRobin is auto ref and it seems that this becomes ref 
in this case. Because I don't know exactly how auto ref is 
supposed to work, I don't know whether this is a bug in DMD or in 
roundRobin.front.


This works:

auto r = roundRobin(arr, repeat(s).take(arr.length - 1).array);

And so does this:

auto r2 = roundRobin(arr.map!"a", repeat(s).take(arr.length - 1));


Re: path matching problem

2012-11-27 Thread Charles Hixson

On 11/27/2012 01:34 PM, jerro wrote:

On Tuesday, 27 November 2012 at 19:40:56 UTC, Charles Hixson wrote:

Is there a better way to do this? (I want to find files that match any
of some extensions and don't match any of several other strings, or
are not in some directories.):

import std.file;

...

string exts = "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
string[] exclude = ["/template/", "biblio.txt", "categories.txt",
"subjects.txt", "/toCDROM/"]

int limit = 1
// Iterate a directory in depth
foreach (string name; dirEntries(sDir, exts, SpanMode.depth))
{ bool excl = false;
foreach (string part; exclude)
{ if (part in name)
{ excl = true;
break;
}
}
if (excl) break;
etc.


You could replace the inner loop with somehting like:

bool excl = exclude.any!(part => name.canFind(part));

There may be even some easier way to do it, take a look at std.algorithm.


std.algorithm seems to generally be running the match in the opposite 
direction, if I'm understanding it properly.  (Dealing with D template 
is always confusing to me.)  OTOH, I couldn't find the string any 
method, so I'm not really sure what you're proposing, though it does 
look attractive.


Still, though your basic approach sounds good, the suggestion of Joshua 
Niehus would let me filter out the strings that didn't fit before 
entering the loop.  There's probably no real advantage to doing it that 
way, but it does seem more elegant.  (You were right, though.  That is 
in std.algorithms.)


Re: path matching problem

2012-11-27 Thread Joshua Niehus
On Tuesday, 27 November 2012 at 23:43:43 UTC, Charles Hixson 
wrote:
But why the chained filters, rather than using the option 
provided by dirEntries for one of them?  Is it faster?  Just 
the way you usually do things? (Which I accept as a legitimate 
answer.  I can see that that approach would be more flexible.)


Ignorance...
Your right, I didn't realize that dirEntries had that filter 
option, you should use that.  I doubt the double .filter would 
effect performance at all (might even slow it down for all i know 
:)


//update:
import std.algorithm, std.array, std.regex;
import std.stdio, std.file;
void main()
{
  string exts = "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
  enum string exclude =

`r"/template/|biblio\.txt|categories\.txt|subjects\.txt|/toCDROM/"`;


  dirEntries("/path", exts, SpanMode.depth)
.filter!(` std.regex.match(a.name,` ~ exclude ~ `).empty `)
.writeln();
}



Re: path matching problem

2012-11-27 Thread Charles Hixson

On 11/27/2012 01:31 PM, Joshua Niehus wrote:

On Tuesday, 27 November 2012 at 19:40:56 UTC, Charles Hixson wrote:

Is there a better way to do this? (I want to find files that match any
of some extensions and don't match any of several other strings, or
are not in some directories.):

import std.file;

...

string exts = "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
string[] exclude = ["/template/", "biblio.txt", "categories.txt",
"subjects.txt", "/toCDROM/"]

int limit = 1
// Iterate a directory in depth
foreach (string name; dirEntries(sDir, exts, SpanMode.depth))
{ bool excl = false;
foreach (string part; exclude)
{ if (part in name)
{ excl = true;
break;
}
}
if (excl) break;
etc.


maybe this:?

import std.algorithm, std.array, std.regex;
import std.stdio, std.file;
void main()
{
enum string[] exts = [`".txt"`, `".utf8"`, `".utf-8"`, `".TXT"`,
`".UTF8"`, `".UTF-8"`];
enum string exclude =
`r"/template/|biblio\.txt|categories\.txt|subjects\.txt|/toCDROM/"`;

auto x = dirEntries("/path", SpanMode.depth)
.filter!(`endsWith(a.name,` ~ exts.join(",") ~ `)`)
.filter!(`std.regex.match(a.name,` ~ exclude ~ `).empty`);;

writeln(x);
}


That's a good approach, except that I want to step through the matching 
paths rather than accumulate them in a vector...though ... the filter 
documentation could mean that it would return an iterator.  So I could 
replace

writeln (x);
by
foreach (string name; x)
{
...
}
and x wouldn't have to hold all the matching strings at the same time.

But why the chained filters, rather than using the option provided by 
dirEntries for one of them?  Is it faster?  Just the way you usually do 
things? (Which I accept as a legitimate answer.  I can see that that 
approach would be more flexible.)


Re: telnet and D

2012-11-27 Thread maarten van damme
> IIRC, telnet is simple, so it shouldn't be too difficult..
Turns out it indeed was simple. My option negotiation had a bug :D

my (primitive) telnet client works now :)


Re: auto ref and arrays

2012-11-27 Thread Artur Skawina
On 11/27/12 23:44, Ali Çehreli wrote:
> On 11/27/2012 02:09 PM, Jack Applegame wrote:
>> I don't understand why auto ref doesn't work with arrays.
>>
>> void test1(T)(auto ref const T[] val) {}
>> void test2(T)(auto ref const T val) {}
>> void main() {
>> int b;
>> test2(b); // OK
>> string a;
>> test1(a); // Error: cast(const(char[]))a is not an lvalue
>> }
>>
>> Since a is mutable itself, compiler uses ref storage class.
>> cast(const(char[]))a isn't an lvalue, so it's impossible to pass it by ref.
>>
>> But cast(const int)b isn't an lvalue too. Why it's no errors in this case?
> 
> Sorry, I am not answering the question but is 'auto ref' is legal as a 
> parameter? It is not documented.

It's legal and documented: http://dlang.org/template.html

Whether the argument is mutable or not shouldn't matter -- compiler bug;
both examples should compile (limiting auto-ref to only modifiable lvalues
wouldn't make sense).

artur


Re: auto ref and arrays

2012-11-27 Thread Jonathan M Davis
On Tuesday, November 27, 2012 14:44:51 Ali Çehreli wrote:
> On 11/27/2012 02:09 PM, Jack Applegame wrote:
> > I don't understand why auto ref doesn't work with arrays.
> > 
> > void test1(T)(auto ref const T[] val) {}
> > void test2(T)(auto ref const T val) {}
> > void main() {
> > int b;
> > test2(b); // OK
> > string a;
> > test1(a); // Error: cast(const(char[]))a is not an lvalue
> > }
> > 
> > Since a is mutable itself, compiler uses ref storage class.
> > cast(const(char[]))a isn't an lvalue, so it's impossible to pass it by
> > ref.
> > 
> > But cast(const int)b isn't an lvalue too. Why it's no errors in this case?
> 
> Sorry, I am not answering the question but is 'auto ref' is legal as a
> parameter? It is not documented.
> 
> On the other hand, 'auto ref' is a legal return type.

Yes, it's legal on function paramters - but only on templated functions. It 
was an attempt at solving the const& problem. It's supposed to take both 
lvalues and rvalues but not copy lvalues. I think that there's a decent chance 
that TDPL talks about it, but I'm not sure, though if it does, what it 
describes isn't quite what auto ref does at the moment, since the original 
idea for auto ref would have worked with non-templated functions, but Andrei 
and Walter miscommunicated on its intent, and it wasn't implemented that way 
(and would actually be problematic to implement that way).

As for the OP's question, I'd say that it looks like a bug. My guess is that a 
cast is being inserted as part of the auto ref implementation, and a cast does 
_not_ result in an lvalue, so that's why it would fail. I don't know why it 
thinks it needs a cast though.

- Jonathan M Davis


Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Jonathan M Davis
On Tuesday, November 27, 2012 23:35:55 Andrej Mitrovic wrote:
> On 11/27/12, Jonathan M Davis  wrote:
> > Rather, you're asking it to insert an element
> > between
> > every element in range, which is similar but not the same.
> 
> In that case, which function to use? Because it already behaves in
> this way for strings.

But it doesn't. It requires a range of ranges, and a string is a range of 
dchar. You need a range of strings to use join on strings.

assert(join(["hello", "silly", "world"], " ") == "hello silly world");

will work.

assert(join("hello world", " ") == "h e l l o w o r l d");

won't. You seem to be looking for a function which will insert an element 
between every element in a range rather than one that joins ranges, and I'm 
not aware of any function in Phobos which will do that. There may be a way to 
get one to do what you want, but I can't think of how at the moment.

- Jonathan M Davis


Re: auto ref and arrays

2012-11-27 Thread Ali Çehreli

On 11/27/2012 02:09 PM, Jack Applegame wrote:

I don't understand why auto ref doesn't work with arrays.

void test1(T)(auto ref const T[] val) {}
void test2(T)(auto ref const T val) {}
void main() {
int b;
test2(b); // OK
string a;
test1(a); // Error: cast(const(char[]))a is not an lvalue
}

Since a is mutable itself, compiler uses ref storage class.
cast(const(char[]))a isn't an lvalue, so it's impossible to pass it by ref.

But cast(const int)b isn't an lvalue too. Why it's no errors in this case?


Sorry, I am not answering the question but is 'auto ref' is legal as a 
parameter? It is not documented.


On the other hand, 'auto ref' is a legal return type.

Ali


Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Andrej Mitrovic
On 11/27/12, Jonathan M Davis  wrote:
> Rather, you're asking it to insert an element
> between
> every element in range, which is similar but not the same.

In that case, which function to use? Because it already behaves in
this way for strings.


auto ref and arrays

2012-11-27 Thread Jack Applegame

I don't understand why auto ref doesn't work with arrays.

void test1(T)(auto ref const T[] val) {}
void test2(T)(auto ref const T val) {}
void main() {
  int b;
  test2(b); // OK
  string a;
  test1(a); // Error: cast(const(char[]))a is not an lvalue
}

Since a is mutable itself, compiler uses ref storage class.
cast(const(char[]))a isn't an lvalue, so it's impossible to pass 
it by ref.


But cast(const int)b isn't an lvalue too. Why it's no errors in 
this case?


Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Jonathan M Davis
On Tuesday, November 27, 2012 13:05:12 Andrej Mitrovic wrote:
> On 11/27/12, Jonathan M Davis  wrote:
> > All you need to do is put it in an array.
> > 
> > arr.join([s]);
> 
> Still doesn't work.
> 
> > S[1] s = void;
> > s[0] = S(0);
> > arr.join(s[]);
> 
> Neither does that.
> 
> http://d.puremagic.com/issues/show_bug.cgi?id=9082

Oh, wait. The problem is that you're calling join on something that isn't a 
range of ranges. It makes no sense to join an array which doesn't hold ranges. 
There's nothing to join. Rather, you're asking it to insert an element between 
every element in range, which is similar but not the same.

- Jonathan M Davis


Re: path matching problem

2012-11-27 Thread jerro
On Tuesday, 27 November 2012 at 19:40:56 UTC, Charles Hixson 
wrote:
Is there a better way to do this?  (I want to find files that 
match any of some extensions and don't match any of several 
other strings, or are not in some directories.):


 import std.file;

...

 string  exts  =  "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
 string[]  exclude  =  ["/template/",  "biblio.txt",  
"categories.txt",

"subjects.txt",  "/toCDROM/"]

 int  limit  =  1
 //  Iterate  a  directory  in  depth
 foreach  (string  name;  dirEntries(sDir,  exts,  
SpanMode.depth))

 {  bool  excl  =  false;
foreach  (string  part;  exclude)
{  if  (part  in  name)
   {  excl  =  true;
  break;
   }
}
if  (excl)  break;
etc.


You could replace the inner loop with somehting like:

bool excl = exclude.any!(part => name.canFind(part));

There may be even some easier way to do it, take a look at 
std.algorithm.


Re: path matching problem

2012-11-27 Thread Joshua Niehus
On Tuesday, 27 November 2012 at 19:40:56 UTC, Charles Hixson 
wrote:
Is there a better way to do this?  (I want to find files that 
match any of some extensions and don't match any of several 
other strings, or are not in some directories.):


 import std.file;

...

 string  exts  =  "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
 string[]  exclude  =  ["/template/",  "biblio.txt",  
"categories.txt",

"subjects.txt",  "/toCDROM/"]

 int  limit  =  1
 //  Iterate  a  directory  in  depth
 foreach  (string  name;  dirEntries(sDir,  exts,  
SpanMode.depth))

 {  bool  excl  =  false;
foreach  (string  part;  exclude)
{  if  (part  in  name)
   {  excl  =  true;
  break;
   }
}
if  (excl)  break;
etc.


maybe this:?

import std.algorithm, std.array, std.regex;
import std.stdio, std.file;
void main()
{
enum string[] exts  =  [`".txt"`, `".utf8"`, `".utf-8"`, 
`".TXT"`, `".UTF8"`, `".UTF-8"`];
enum string exclude = 
`r"/template/|biblio\.txt|categories\.txt|subjects\.txt|/toCDROM/"`;


auto x = dirEntries("/path", SpanMode.depth)
.filter!(`endsWith(a.name,` ~ exts.join(",") ~ `)`)
.filter!(`std.regex.match(a.name,` ~ exclude ~ 
`).empty`);;


writeln(x);
}


Re: telnet and D

2012-11-27 Thread maarten van damme
Haven't looked at vibe.d yet because it looked more like a library for
writing web apps and  normal sockets should be enough.


Didn't know about Tango, I'll try deciphering the original d1 module.


path matching problem

2012-11-27 Thread Charles Hixson
Is there a better way to do this?  (I want to find files that match any 
of some extensions and don't match any of several other strings, or are 
not in some directories.):


 import std.file;

...

 string  exts  =  "*.{txt,utf8,utf-8,TXT,UTF8,UTF-8}";
 string[]  exclude  =  ["/template/",  "biblio.txt",  "categories.txt",
"subjects.txt",  "/toCDROM/"]

 int  limit  =  1
 //  Iterate  a  directory  in  depth
 foreach  (string  name;  dirEntries(sDir,  exts,  SpanMode.depth))
 {  bool  excl  =  false;
foreach  (string  part;  exclude)
{  if  (part  in  name)
   {  excl  =  true;
  break;
   }
}
if  (excl)  break;
etc.


Re: SList/DList ranges

2012-11-27 Thread Zhenya
On Tuesday, 27 November 2012 at 07:51:16 UTC, Jonathan M Davis 
wrote:

On Monday, November 26, 2012 19:49:51 Zhenya wrote:

Hi!
I read the spec,but I didn't find any function,that removes
concrete element from
list.I am not familiar with D's ranges,so could you help me
please?


What do you mean by removing concrete elements? How is that any 
different from
any other element in the list? If you want to remove elements 
from the list,
then use one of the *remove functions. [] on the list to get a 
range over all
of the elements in the list, find to find the element that you 
want, and then
take to get a range with just the elements from the front of 
the range that

you want to remove. Hopefully this will enlighten you somewhat:

import std.algorithm;
import std.container;
import std.range;
import std.stdio;

void main()
{
auto list = make!(SList!int)(4, 5, 6, 7, 22, 9, 5, 4);
assert(equal(list[], [4, 5, 6, 7, 22, 9, 5, 4]));
auto found = find(list[], 6);
assert(equal(found.save, [6, 7, 22, 9, 5, 4]));
list.linearRemove(take(found, 3));
assert(equal(list[], [4, 5, 9, 5, 4]));
list.linearRemove(take(find(list[], 5), 1));
assert(equal(list[], [4, 9, 5, 4]));
}

Unfortunately, std.container needs a fair bit of work in terms 
of some of the
details - particularly with its functions which accept and/or 
return ranges,
so it doesn't always work like it should yet. It's very much a 
work in
progress right now. But the above should give you the basic 
idea.


As for ranges in general, the best resource on them at this 
point would be

this chapter from an online book on D:

http://ddili.org/ders/d.en/ranges.html

If you're going to be using Phobos much (which is likely if 
you're using D),
then you're going to need to understand ranges, because Phobos 
uses them quite

heavily.

- Jonathan M Davis


Thank you,understood.I just want a container with fast 
insert/remove.Something like C++ std::list.But when I look at you 
example I understand that remove is linear,so maybe I need 
assosiative array or RedBlackTree.

And thank you for a link,I will learn ranges surely.



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Maxim Fomin

On Tuesday, 27 November 2012 at 18:30:07 UTC, Ali Çehreli wrote:
Same problem under Linux. Somebody, please file this bug! Thank 
you! :)


Ali


http://d.puremagic.com/issues/show_bug.cgi?id=9084



Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Ali Çehreli

On 11/27/2012 10:04 AM, Maxim Fomin wrote:

On Monday, 26 November 2012 at 22:42:53 UTC, Dan wrote:

On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton Wakeling
wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:


Ok, now I really want to know why it crashes. I've narrowed it down to
an example below. It seems there is a problem with RefCounted being
used as value in a map.




I think it crashes because of using associative array. Assignment to an
absent aa member causes memory allocation without proper object
construction, and immediately after compiler issues call to opAssign for
not-constructed object - that is why "this" pointer is "bogus" on
entering function.

import std.stdio;

struct S
{
int i = 42;
struct SS
{
int ii = 41;
this(this) { writeln("SS postblit"); }
void opAssign(SS rhs) { writeln("SS opAssign"); }
}
SS ss;
this(this) { writeln("S postblit"); }
void opAssign(S rhs)
{
writeln("S opAssign");
}
~this()
{
writefln("i=%d, ii=%d", i, ss.ii);
}
}

S[int] map ;
// S[2] map;
// S[] map = [S(), S()];

void main()
{
map[1] = S();
}

AA version on windows 2.060 prints

SS postblit
S opAssign
i=42, ii=41
i=4269990, ii=4269984 //garbage

Switching to dynamic or static array fixes the program.


Same problem under Linux. Somebody, please file this bug! Thank you! :)

Ali


Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Maxim Fomin

On Monday, 26 November 2012 at 22:42:53 UTC, Dan wrote:
On Monday, 26 November 2012 at 19:14:09 UTC, Joseph Rushton 
Wakeling wrote:

On 11/26/2012 04:07 PM, Joseph Rushton Wakeling wrote:


Ok, now I really want to know why it crashes. I've narrowed it 
down to an example below. It seems there is a problem with 
RefCounted being used as value in a map.





I think it crashes because of using associative array. Assignment 
to an absent aa member causes memory allocation without proper 
object construction, and immediately after compiler issues call 
to opAssign for not-constructed object - that is why "this" 
pointer is "bogus" on entering function.


import std.stdio;

struct S
{
int i = 42;
struct SS
{
int ii = 41;
this(this) { writeln("SS postblit"); }
void opAssign(SS rhs) { writeln("SS opAssign"); }
}
SS ss;
this(this) { writeln("S postblit"); }
void opAssign(S rhs)
{
writeln("S opAssign");
}
~this()
{
writefln("i=%d, ii=%d", i, ss.ii);
}
}

S[int] map ;
// S[2] map;
// S[] map = [S(), S()];

void main()
{
map[1] = S();
}

AA version on windows 2.060 prints

SS postblit
S opAssign
i=42, ii=41
i=4269990, ii=4269984 //garbage

Switching to dynamic or static array fixes the program.


Re: Calls to struct methods and immutable

2012-11-27 Thread Dan
On Tuesday, 27 November 2012 at 14:05:37 UTC, Joseph Rushton 
Wakeling wrote:

On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote:
... so the real issue here seems to be that there's no 
canonical way (that I can find) to idup an _associative_ array.


I'm using a custom gdup that recursively copies fields and 
requires no support from nested structs. If a dup is provided by 
a struct it will be called. No guarantees, but have a look. 
https://github.com/patefacio/d-help/blob/master/d-help/opmix/mix.d


The following runs:

--
import std.stdio;
import std.typecons;
import std.conv;
import std.exception;
import opmix.mix;

alias Tuple!(uint, "id") Link;

struct Node
{
  uint id;
  Link[] links;

  void addLink(uint l)
  {
links ~= Link(l);
  }

  immutable(Node) idup() pure const @property
  {
auto linkCopy = to!(Link[])(links);
immutable ilinks = assumeUnique(linkCopy);
return immutable(Node)(id, ilinks);
  }
}


struct Network
{
  Node[uint] nodes;

  immutable(Network) idup() pure const @property
  {
auto nodeCopy = nodes.gdup;
immutable imnodes = assumeUnique(nodeCopy);
return immutable(Network)(imnodes);
  }

  void add(uint i, uint j)
  {
if((i in nodes) is null)
  nodes[i] = Node(i);
if((j in nodes) is null)
  nodes[j] = Node(j);

nodes[i].addLink(j);
nodes[j].addLink(i);
  }

  void print()
  {
foreach(k; nodes.keys)
  {
write("[", k, "]");
foreach(l; nodes[k].links)
  write(" ", l.id);
writeln();
  }
writeln();
  }
}

unittest {
  auto n1 = Node(1);

  n1.addLink(5);
  n1.addLink(6);
  writeln(n1.links);

  immutable n2 = n1.idup;
  writeln(n2.links);

  Network net1;
  net1.add(1,2);
  immutable Network net2 = net1.idup;
  writeln(net1);
  writeln(net2);
}



Re: Calls to struct methods and immutable

2012-11-27 Thread Joseph Rushton Wakeling

On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote:

   immutable(Node) idup() pure const @property
   {
 auto linkCopy = to!(Link[])(links);
 immutable ilinks = assumeUnique(linkCopy);
 return immutable(Node)(id, ilinks);
   }


Actually I'm being overly complicated here as with dynamic arrays I can simply 
do,

immutable(Node) idup() pure const @property
{
  return immutable(Node)(id, links.idup);
}

... so the real issue here seems to be that there's no canonical way (that I can 
find) to idup an _associative_ array.


Re: Calls to struct methods and immutable

2012-11-27 Thread Joseph Rushton Wakeling

On 11/16/2012 05:51 AM, Ali Çehreli wrote:

If makeFoo() were not pure, and in general, Foo may need to provide an .idup
member function:


I've been trying this out and ran into some problems with the to!()() 
conversion.

Here's a concrete example.  Suppose I have a couple of structs which are 
designed respectively to represent nodes in a network, and a collection of those 
nodes:


///
alias Tuple!(uint, "id") Link;

struct Node
{
  uint id;
  Link[] links;

  void addLink(uint l)
  {
links ~= Link(l);
  }

  immutable(Node) idup() pure const @property
  {
auto linkCopy = to!(Link[])(links);
immutable ilinks = assumeUnique(linkCopy);
return immutable(Node)(id, ilinks);
  }
}


struct Network
{
  Node[uint] nodes;

  void add(uint i, uint j)
  {
if((i in nodes) is null)
  nodes[i] = Node(i);
if((j in nodes) is null)
  nodes[j] = Node(j);

nodes[i].addLink(j);
nodes[j].addLink(i);
  }

  void print()
  {
foreach(k; nodes.keys)
{
  write("[", k, "]");
  foreach(l; nodes[k].links)
write(" ", l.id);
  writeln();
}
writeln();
  }
}
///

Now, the idup() command for Node works just fine:

  auto n1 = Node(1);

  n1.addLink(5);
  n1.addLink(6);
  writeln(n1.links);

  immutable n2 = n1.idup;
  writeln(n2.links);

...  but if I try to introduce a similar function for the Network struct,

  immutable(Network) idup() pure const @property
  {
auto nodeCopy = to!(Node[uint])(nodes);
immutable imnodes = assumeUnique(nodeCopy);
return immutable(Network)(imnodes);
  }

it fails to compile with an error relating to the to!(Node[uint])() conversion:

-
/opt/dmd/include/d2/std/conv.d(269): Error: template std.conv.toImpl does not 
match any function template declaration. Candidates are:
/opt/dmd/include/d2/std/conv.d(325):std.conv.toImpl(T, S)(S value) if 
(isImplicitlyConvertible!(S, T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
/opt/dmd/include/d2/std/conv.d(431):std.conv.toImpl(T, S)(ref S s) if 
(isRawStaticArray!(S))
/opt/dmd/include/d2/std/conv.d(445):std.conv.toImpl(T, S)(S value) if 
(is(S : Object) && !is(T : Object) && !isSomeString!(T) && hasMember!(S, "to") 
&& is(typeof(S.init.to!(T)()) : T))
/opt/dmd/include/d2/std/conv.d(466):std.conv.toImpl(T, S)(S value) if 
(is(typeof(S.init.opCast!(T)()) : T) && !(isSomeString!(T) && !is(T == enum) && 
!isAggregateType!(T)))
/opt/dmd/include/d2/std/conv.d(497):std.conv.toImpl(T, S)(S value) if 
(!isImplicitlyConvertible!(S, T) && is(T == struct) && is(typeof(T(value

/opt/dmd/include/d2/std/conv.d(269):... (16 more, -v to show) ...
/opt/dmd/include/d2/std/conv.d(325): Error: template std.conv.toImpl cannot 
deduce template function from argument types !(Node)(const(Node))
/opt/dmd/include/d2/std/conv.d(269): Error: template instance toImpl!(Node) 
errors instantiating template
/opt/dmd/include/d2/std/conv.d(1387): Error: template instance 
std.conv.to!(Node).to!(const(Node)) error instantiating
/opt/dmd/include/d2/std/conv.d(269):instantiated from here: 
toImpl!(Node[uint], const(Node[uint]))

inodes.d(41):instantiated from here: to!(const(Node[uint]))
/opt/dmd/include/d2/std/conv.d(269): Error: template instance 
std.conv.toImpl!(Node[uint], const(Node[uint])) error instantiating

inodes.d(41):instantiated from here: to!(const(Node[uint]))
inodes.d(41): Error: template instance 
std.conv.to!(Node[uint]).to!(const(Node[uint])) error instantiating

-

I'm guessing this means I have to define a custom opCast (for Node, I guess) but 
the documentation on how to do so seems sparse -- can you advise?


Full code example attached.

Thanks & best wishes,

 -- Joe
import std.conv, std.exception, std.stdio, std.typecons;

alias Tuple!(uint, "id") Link;

struct Node
{
	uint id;
	Link[] links;

	void addLink(uint l)
	{
		links ~= Link(l);
	}

	immutable(Node) idup() pure const @property
	{
		auto linkCopy = to!(Link[])(links);
		immutable ilinks = assumeUnique(linkCopy);
		return immutable(Node)(id, ilinks);
	}
}

struct Network
{
	Node[uint] nodes;

	void add(uint i, uint j)
	{
		if((i in nodes) is null)
			nodes[i] = Node(i);
		if((j in nodes) is null)
			nodes[j] = Node(j);

		nodes[i].addLink(j);
		nodes[j].addLink(i);
	}

	// Won't compile
	immutable(Network) idup() pure const @property
	{
		auto nodeCopy = to!(Node[uint])(nod

Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Andrej Mitrovic
On 11/27/12, Jonathan M Davis  wrote:
> All you need to do is put it in an array.
>
> arr.join([s]);

Still doesn't work.

> S[1] s = void;
> s[0] = S(0);
> arr.join(s[]);

Neither does that.

http://d.puremagic.com/issues/show_bug.cgi?id=9082


Re: type determination

2012-11-27 Thread dsmith
On Tuesday, 27 November 2012 at 10:45:19 UTC, Jonathan M Davis 
wrote:

On Tuesday, November 27, 2012 11:30:31 dsmith wrote:

Oh, the "static if" ... for compile time evaluation; seems
unintuitive (no?) since data is encountered at run time.


But the types are known at compile time. If you're doing 
anything with types,

it has to be done at compile time.

- Jonathan M Davis


Indeed, based on the parameter in the function call.




Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Jonathan M Davis
On Tuesday, November 27, 2012 02:33:00 Andrej Mitrovic wrote:
> This is what I want:
> 
> struct S { int x; }
> 
> void main()
> {
> S[] arr = [S(2), S(4), S(6)];
> S s = S(0);
> arr.join(s);  // fails here
> assert(arr == [S(2), S(0), S(4), S(0), S(6)]);
> }
> 
> Calling join like that fails, specifically it fails because "s" is not
> a forward range (I don't know why it's implemented like that..). Is
> there some other function which can join with an element as a
> separator?

All you need to do is put it in an array.

arr.join([s]);

should work just fine. Or, if you don't want to allocate on the heap, you could 
do

S[1] s = void;
s[0] = S(0);
arr.join(s[]);

Granted, it _is_ a bit odd that join doesn't accept an element (and I don't 
think that it's the only range-based function with this problem), but it's 
easy enough to turn a single element into a range if you need to.

- Jonathan M Davis


Re: What to use instead of array.join if RHS is not a range?

2012-11-27 Thread Andrej Mitrovic
On 11/27/12, H. S. Teoh  wrote:
> What about std.algorithm.joiner?

Same problem.

Anyway here's a quick lazy (pun intended) implementation:

import std.array;
import std.stdio;

struct MyJoiner(T)
{
T[] array;
T sep;

@property bool empty() { return array.empty; }

void popFront()
{
if (!useSep)
array.popFront();

useSep ^= 1;
}

bool useSep;
@property T front()
{
if (useSep)
return sep;
else
return array.front;
}
}

auto myJoiner(T)(T[] array, T sep)
{
return MyJoiner!T(array, sep);
}

struct S { int x; }

void main()
{
S[] arr = [S(2), S(4), S(6)];
S s = S(0);
auto range = arr.myJoiner(s);
assert(array(range) == [S(2), S(0), S(4), S(0), S(6)]);
}


Re: type determination

2012-11-27 Thread Jonathan M Davis
On Tuesday, November 27, 2012 11:30:31 dsmith wrote:
> Oh, the "static if" ... for compile time evaluation; seems
> unintuitive (no?) since data is encountered at run time.

But the types are known at compile time. If you're doing anything with types, 
it has to be done at compile time.

- Jonathan M Davis


Re: type determination

2012-11-27 Thread dsmith
On Tuesday, 27 November 2012 at 07:28:34 UTC, Jacob Carlborg 
wrote:

On 2012-11-27 06:03, dsmith wrote:
How can I make something like the following work without 
"Error: cannot

append type double to type string[]" ?


T[] some_function(T[] var) {
 T[] var2;
 double a = 12.34;
 string b = "hello";

 if(typeof(var).stringof == "double") {
   var2 ~= a;
 }
 if(typeof(var).stringof == "string") {
   var2 ~= b;
 }

...
}


Use static-if, but you shouldn't use .stringof. Check the 
actual type and not the string of the type:


static if(is(typeof(var) == double)) {
var2 ~= a;
}

static if(is(typeof(var) == string)) {
var2 ~= b;
}


Oh, the "static if" ... for compile time evaluation; seems 
unintuitive (no?) since data is encountered at run time.




Re: Segfault with std.container.Array but not regular dynamic array

2012-11-27 Thread Joseph Rushton Wakeling

On 11/26/2012 11:42 PM, Dan wrote:

Ok, now I really want to know why it crashes. I've narrowed it down to an
example below. It seems there is a problem with RefCounted being used as value
in a map.


I don't have the expertise to understand the assembly, but just to note that 
even with all the structs converted to classes, nodes.d only compiles with dmd. 
 With ldmd2 or gdmd it exits with an error:


container.d:2248: Error: cannot compare const(Tuple!(uint,"id")[]) and 
const(Tuple!(uint,"id")[])


... regardless of whether Node1 and Node2 are declared as structs or classes.



Re: #define trouble

2012-11-27 Thread dnewbie

On Tuesday, 27 November 2012 at 06:27:49 UTC, Ali Çehreli wrote:

On 11/26/2012 10:05 PM, dnewbie wrote:

I have the following C struct from ldap.h

typedef struct ldapmod {
int mod_op;
char *mod_type;
union mod_vals_u {
char **modv_strvals;
struct berval **modv_bvals;
} mod_vals;
#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals
} LDAPMod;

It is used like this:
LDAPMod title;
title.mod_values = x;

I wonder how can I write the line 'title.mod_values = x;' in D.
Currently I do like this:

struct ldapmod {
int mod_op;
char* mod_type;
union mod_vals_u {
char** modv_strvals;
berval** modv_bvals;
}
mod_vals_u mod_vals;
}
alias ldapmod LDAPMod;

LDAPMod title;
title.mod_vals.modv_strvals = x;




A pair of @property functions would work, one of which may be 
unnecessary:


alias int berval;

struct ldapmod {
intmod_op;
char* mod_type;
union mod_vals_u {
char**  modv_strvals;
berval** modv_bvals;
}
mod_vals_u mod_vals;

char** mod_values() @property
{
return mod_vals.modv_strvals;
}

void mod_values(char** value) @property
{
mod_vals.modv_strvals = value;
}

// similarly for mod_bvalues...
}
alias ldapmod LDAPMod;

void main()
{
LDAPMod title;
char** x;
// title.mod_vals.modv_strvals = x;
title.mod_values = x;
}


Ali



Perfect! Thank you.