Re: one liner to split a string into every n chars?

2022-04-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 4/13/22 2:26 AM, mw wrote:

Hi,

What's the D's idiom to split a string into an array of every n chars? 
(prefer one liner)


str.byChar.chunks(2).array;

Your request of "array of every n chars" is somewhat ambiguous. This is 
an array of chunks (not an array of arrays).


-Steve


Re: Why do immutable variables need reference counting?

2022-04-13 Thread Ali Çehreli via Digitalmars-d-learn

On 4/12/22 21:34, Salih Dincer wrote:

> I tried the following and I didn't understand one thing: Why is there no
> need to use dup when slicing?

I don't think I understand you fully.

> ```d
> struct S(T) {
>   T fileName;
>
>this(T fileName) {
>  this.fileName = fileName;
>  report();
>}
>
>~this() { report(); }
>
>void report(string func = __FUNCTION__) {
>  import std.stdio;
>  writefln!"%s\nworking with %s"(func, fileName);
>}
> }
> alias T1 = const(char)[];
> alias T2 = const char[];
> alias T3 = const(char[]); // T3 == T2
> alias T4 = immutable char[]; // Not compiling!
>
>
> void main() {
>auto fileName = "foo.txt".dup;

In every test case that 'fileName' is char[].

>auto s = S!T1(fileName);
>fileName[0..3] = "bar";

For that reason, that expression will always succeed. And that's the 
point I tried to make: Without immutable, struct S *must* make a copy in 
order to guarantee that its member will remain the same.


> }/* Results:

[...]

>*
>*T4
>*
>Error: slice `fileName[0..3]` is not mutable

Your code was different because I get an error that I expect: The 
following line fails.


  auto s = S!T4(fileName);

cannot pass argument `fileName` of type `char[]` to parameter 
`immutable(string) fileName`


Exactly! struct S wants immutable (to guarantee that nobody will mutate 
it) but 'fileName' in main is not immutable. You can make it pass in the 
T4 case


a) by making an immutable copy with .idup:

  auto s = S!T4(fileName.idup);

b) by converting 'fileName' to immutable without a copy:

  import std.exception;
  auto s = S!T4(fileName.assumeUnique);
  // But then, the following will fail. Awesome!
  // fileName[0..3] = "bar";

I am amazed everyday how great D is; such a fun engineering tool!

Ali



Re: Why do immutable variables need reference counting?

2022-04-13 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Apr 13, 2022 at 08:39:17AM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
> On 4/12/22 21:34, Salih Dincer wrote:
> 
> > I tried the following and I didn't understand one thing: Why is
> > there no need to use dup when slicing?
[...]

Because of two things: (1) there is a GC, and (2) characters in a string
are immutable.

Without (1), you will end up with either a memory leak or a dangling
pointer; without (2), your slice may randomly mutate when you don't
expect it to.


T

-- 
May you live all the days of your life. -- Jonathan Swift


RefCounted

2022-04-13 Thread JG via Digitalmars-d-learn

Hi,

I would have thought that RefCounted!(T, 
RefCountedAutoInitialize.no) is to be used in place T* when I 
want reference counting instead of the usual garbage collection 
(or manual allocation). Perhaps this is wrong?


If I am correct what am I doing wrong here?

(Sorry for two space squashed style).

```
import std.stdio;
import std.typecons;

struct Node(T) {
  RefCounted!(Node!T, RefCountedAutoInitialize.no) next;
  T val;
}

struct List(T) {
  RefCounted!(Node!T, RefCountedAutoInitialize.no) head;
  bool empty() { return head.refCountedStore.isInitialized; }
  T front() { return head.val; }
  void popFront() { head = head.next; }
  typeof(this) save() { return typeof(this)(head); }
}

void main() {
  List!long l;
}
```
I also tried my own implementation but that is not working (since 
not everything is being freed) and probably
relies on undefined behavior with my casting away inout, which I 
did because
otherwise the compiler kept giving me errors about not being able 
to generate a copy constructor for List.


```
import std.stdio;
import core.stdc.stdlib;


private struct RefCountedPointer(T) {
  static struct Payload(T) {
long cnt=1;
T val;
  }
  Payload!T* ptr;
  this(T x) {
ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof);
*ptr = Payload!T(1,x);
  }
  ~this() {
if(ptr==null) { return; }
(*ptr).cnt--;
if((*ptr).cnt == 0) {
  ptr.val.destroy();
  free(ptr);
}
  }
  @disable this(ref return scope immutable(typeof(this)) rhs);
  this(ref return scope inout(typeof(this)) rhs) {
ptr = cast(Payload!T*) rhs.ptr;
if(ptr==null) { return; }
ptr.cnt++;
  }
  void opAssign(typeof(this) rhs) {
if(this.ptr!=null) { (*this.ptr).cnt--; }
this.ptr = rhs.ptr;
if(this.ptr!=null) { (*this.ptr).cnt++; }
  }
  bool isNull() { return ptr==null; }
  ref auto dref() { assert(!isNull); return (*ptr).val; }
}

private struct Node(T) {
  RefCountedPointer!(Node!T) next;
  T val;
}


struct List(T) {
  private RefCountedPointer!(Node!T) head;
  bool empty() { return head.isNull; }
  T front() { return head.dref.val; }
  void popFront()  { head = head.dref.next;  }
  auto save() { return typeof(this)(head); }
  auto insert(T x) {
head = RefCountedPointer!(Node!T)(Node!T(head,x));
  }
}

void main() {
  List!long list;
  list.insert(8);
import std.stdio;
import core.stdc.stdlib;


private struct RefCountedPointer(T) {
  static struct Payload(T) {
long cnt=1;
T val;
  }
  Payload!T* ptr;
  this(T x) {
ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof);
*ptr = Payload!T(1,x);
  }
  ~this() {
if(ptr==null) { return; }
(*ptr).cnt--;
if((*ptr).cnt == 0) {
  writeln("free");
  ptr.val.destroy();
  free(ptr);
}
  }
  @disable this(ref return scope immutable(typeof(this)) rhs);
  this(ref return scope inout(typeof(this)) rhs) {
ptr = cast(Payload!T*) rhs.ptr;
if(ptr==null) { return; }
ptr.cnt++;
  }
  void opAssign(typeof(this) rhs) {
"here".writeln;
if(this.ptr!=null) { (*this.ptr).cnt--; }
this.ptr = rhs.ptr;
if(this.ptr!=null) { (*this.ptr).cnt++; }
  }
  bool isNull() { return ptr==null; }
  ref auto dref() { assert(!isNull); return (*ptr).val; }
}

private struct Node(T) {
  RefCountedPointer!(Node!T) next;
  T val;
}


struct List(T) {
  private RefCountedPointer!(Node!T) head;
  bool empty() { return head.isNull; }
  T front() { return head.dref.val; }
  void popFront()  { head = head.dref.next;  }
  auto save() { return typeof(this)(head); }
  auto insert(T x) {
head = RefCountedPointer!(Node!T)(Node!T(head,x));
  }
}

void main() {
  List!long list;
  list.insert(8);
import std.stdio;
import core.stdc.stdlib;


private struct RefCountedPointer(T) {
  static struct Payload(T) {
long cnt=1;
T val;
  }
  Payload!T* ptr;
  this(T x) {
ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof);
*ptr = Payload!T(1,x);
  }
  ~this() {
if(ptr==null) { return; }
(*ptr).cnt--;
if((*ptr).cnt == 0) {
  writeln("free");
  ptr.val.destroy();
  free(ptr);
}
  }
  @disable this(ref return scope immutable(typeof(this)) rhs);
  this(ref return scope inout(typeof(this)) rhs) {
ptr = cast(Payload!T*) rhs.ptr;
if(ptr==null) { return; }
ptr.cnt++;
  }
  void opAssign(typeof(this) rhs) {
"here".writeln;
if(this.ptr!=null) { (*this.ptr).cnt--; }
this.ptr = rhs.ptr;
if(this.ptr!=null) { (*this.ptr).cnt++; }
  }
  bool isNull() { return ptr==null; }
  ref auto dref() { assert(!isNull); return (*ptr).val; }
}

private struct Node(T) {
  RefCountedPointer!(Node!T) next;
  T val;
}


struct List(T) {
  private RefCountedPointer!(Node!T) head;
  bool empty() { return head.isNull; }
  T front() { return head.dref.val; }
  void popFront()  { head = head.dref.next;  }
  auto save() { return typeof(this)(head); }
  auto insert(T x) {
head = RefCountedPointer!(Node!T)(Node!T(head,x));
  }
}

void main() {
  List!long list;
  list.insert(8);
  list.

Re: RefCounted

2022-04-13 Thread JG via Digitalmars-d-learn

On Wednesday, 13 April 2022 at 20:47:33 UTC, JG wrote:

Hi,

I would have thought that RefCounted!(T, 
RefCountedAutoInitialize.no) is to be used in place T* when I 
want reference counting instead of the usual garbage collection 
(or manual allocation). Perhaps this is wrong?


[...]


Perhaps I should have added in case it is relevant, I am not 
actually interested in building lists. I eventually want to use 
this in a "persistent" version of a red black tree (where if r is 
such a tree and we set r1=r.insert(x) then r is unaffected and r1 
has the new element inserted - but they share most nodes). This 
data structure is to be used in a multithreaded application 
searching for a solution to some problem. The current version has 
bad performance seemingly due to gc stopping all threads while 
freeing unused nodes.


Re: RefCounted

2022-04-13 Thread Salih Dincer via Digitalmars-d-learn

On Wednesday, 13 April 2022 at 21:15:13 UTC, JG wrote:

On Wednesday, 13 April 2022 at 20:47:33 UTC, JG wrote:

Hi,

I would have thought that RefCounted!(T, 
RefCountedAutoInitialize.no) is to be used in place T* when I 
want reference counting instead of the usual garbage 
collection (or manual allocation). Perhaps this is wrong?


[...]


Perhaps I should have added in case it is relevant, I am not 
actually interested in building lists. I eventually want to use 
this in a "persistent" version of a red black tree (where if r 
is such a tree and we set r1=r.insert(x) then r is unaffected 
and r1 has the new element inserted - but they share most 
nodes). This data structure is to be used in a multithreaded 
application searching for a solution to some problem. The 
current version has bad performance seemingly due to gc 
stopping all threads while freeing unused nodes.


I don't know what RefCount is for but  I fixed your codes that 
mixed up:


```d
import std.stdio;
import core.stdc.stdlib;

 private struct RefCountedPointer(T) {
   static struct Payload(T) {
 int cnt = 1;
 T val;
   }

   Payload!T* ptr;

   this(T x) {
 ptr = cast(Payload!T*) calloc(0, Payload!T.sizeof);
 *ptr = Payload!T(1, x);
   }

   ~this() {
 if(ptr == null) {
   return;
 }
 (*ptr).cnt--;

 if((*ptr).cnt == 0) {
   writeln("free");
   ptr.val.destroy();
   free(ptr);
 }
   }

   @disable
   this(ref return scope immutable(typeof(this)) rhs);

   this(ref return scope inout(typeof(this)) rhs) {
 ptr = cast(Payload!T*) rhs.ptr;
 if(ptr == null) {
   return;
 }
 ptr.cnt++;
   }

   void opAssign(typeof(this) rhs) {
 "here".writeln;
 if(this.ptr != null) {
   (*this.ptr).cnt--;
 }

 this.ptr = rhs.ptr;

 if(this.ptr != null) {
   (*this.ptr).cnt++;
 }
   }

   bool isNull() {
 return ptr == null;
   }

   ref auto dref() {
 assert(!isNull);
 return (*ptr).val;
   }
 }

 struct List(T) {
   private RefCountedPointer!(Node!T) head;
   bool empty() { return head.isNull; }
   T front() { return head.dref.val; }
   void popFront()  { head = head.dref.next;  }
   auto save() { return typeof(this)(head); }
   auto insert(T x) { head = 
RefCountedPointer!(Node!T)(Node!T(head,x)); }

 }

 private struct Node(T) {
   RefCountedPointer!(Node!T) next;
   T val;
 }

void main()
{
   List!long list;
   list.insert(8);
   list.insert(7);
   list.insert(6);
   list.insert(5);
   list.insert(4);
   list.popFront;
   list.writeln;
   list.insert(4);
   list.insert(3);
   list.insert(2);
   list.insert(1);
   list.writeln;
}
```