Re: Intellij: Support for TextMate Bundled

2019-07-25 Thread David Bennett via Digitalmars-d-announce

On Thursday, 25 July 2019 at 18:46:00 UTC, bachmeier wrote:
Curious if there are a lot of D programmers using IntelliJ. 
It's $500 just for the first year.


I've been using IntelliJ Idea Community for D development for 
years, mostly for the syntax highlighting, code completion and 
linting. Still use the cli for compilation because nothing beats 
CTRL+R.


I did have some jank issues but now with the LSP support and 
using DLS these seem to be gone now.


The debugger worked the last I tried it but lately I haven't had 
so many runtime D errors that require debuging as I've now use a 
subset of D that tends to work so long as it compiles.


Re: [your code here] 99 bottles of beer

2018-10-15 Thread David Bennett via Digitalmars-d

--- ct_beer.d

static foreach_reverse(beer; 1..100)
{
	pragma(msg, beer, " bottles of beer on the wall, ", beer, " 
bottles of beer. Take one down, pass it around, ", beer-1, " 
bottles of beer on the wall.");

}

void main(){}

---


Re: Phobos begat madness

2018-06-26 Thread David Bennett via Digitalmars-d

On Monday, 25 June 2018 at 01:03:03 UTC, David Bennett wrote:

On Friday, 22 June 2018 at 21:37:07 UTC, Walter Bright wrote:


If someone wants to figure out how to build an uncomplicated, 
straightforward, efficient implementation of text() that we 
can be proud of, that would be a nice contribution.



I will upload the benchmark for `text` tonight.




I have made a more complete benchmark [0] so we can see the speed 
of each basic type.


Here's the benchmark results for dmd:

|---|
|.to!(string) |   .newTo!(string) | 
.writeCharsTo(buf) |

|---|
| ubyte:   1856 ms |   1037 ms | 
201 ms |
| ushort   :   2336 ms |   1350 ms | 
382 ms |
| uint :   3415 ms |   1538 ms | 
669 ms |
| ulong:   6171 ms |   2275 ms |
1398 ms |
| byte :   1908 ms |   1044 ms | 
227 ms |
| short:   2234 ms |   1364 ms | 
406 ms |
| int  :   3560 ms |   1603 ms | 
629 ms |
| long :   6276 ms |   2219 ms |
1369 ms |
| char :   3013 ms |   1061 ms | 
181 ms |
| wchar:   3285 ms |   1043 ms | 
242 ms |
| dchar:   3211 ms |   1048 ms | 
277 ms |

|---|

|---|
|text(...) |  newText(...) | 
.writeCharsTo(buf) |

|---|
| ubyte:   2643 ms |937 ms | 
254 ms |
| ushort   :   3237 ms |   1173 ms | 
530 ms |
| uint :   5144 ms |   1448 ms | 
738 ms |
| ulong:   9854 ms |   2126 ms |
1427 ms |
| byte :   2805 ms |951 ms | 
310 ms |
| short:   3272 ms |   1268 ms | 
583 ms |
| int  :   5548 ms |   1456 ms | 
819 ms |
| long :  10303 ms |   2182 ms |
1488 ms |
| char :   3853 ms |891 ms | 
258 ms |
| wchar:   4151 ms |940 ms | 
263 ms |
| dchar:   3945 ms |949 ms | 
352 ms |

|---|

And ldc2:

|---|
|.to!(string) |   .newTo!(string) | 
.writeCharsTo(buf) |

|---|
| ubyte:   1003 ms |   1011 ms |  
88 ms |
| ushort   :959 ms |772 ms | 
163 ms |
| uint :   1519 ms |   1237 ms | 
382 ms |
| ulong:   2030 ms |   1484 ms | 
735 ms |
| byte :899 ms |886 ms | 
121 ms |
| short:   1115 ms |   1061 ms | 
189 ms |
| int  :   1267 ms |   1041 ms | 
390 ms |
| long :   2030 ms |   1596 ms | 
852 ms |
| char :   1958 ms |755 ms |  
28 ms |
| wchar:   1945 ms |836 ms | 
129 ms |
| dchar:   2141 ms |850 ms | 
142 ms |

|---|

|---|
|text(...) |  newText(...) | 
.writeCharsTo(buf) |

|---|
| ubyte:   1248 ms |448 ms | 
164 ms |
| ushort   :   1676 ms |612 ms | 
290 ms |
| uint :   1491 ms |732 ms | 
445 ms |
| ulong:   2343 ms |   1074 ms |
1095 ms |
| byte :   1288 ms |506 ms | 
143 ms |
| short:   1494 ms |656 ms | 
311 ms |
| int  :   1315 ms |633 ms | 
388 ms |
| long :   2540 ms |   1363 ms |
1044 ms |
| char :   2528 ms |411 ms | 
189 ms |
| wchar:   2600 ms |506 ms | 
149 ms |
| dchar:   2697 ms |452 ms | 
167 ms |

|---|

So I think there are quite a lot 

Re: Disappointing performance from DMD/Phobos

2018-06-25 Thread David Bennett via Digitalmars-d

On Tuesday, 26 June 2018 at 02:10:17 UTC, Manu wrote:

[snip]
  @property uint systemBits() const { return 
systemData[].map!(e =>

e.length).sum; } [snip]

This property sum's 4 ints... that should be insanely fast. It 
should

also be something like 5-8 lines of asm.
Turns out, that call to sum() is eating 2.5% of my total perf
(significant among a substantial workload), and the call tree 
is quite

deep.

Basically, inliner tried, but failed to seal the deal, and 
leaves a call stack 7 levels deep.


Last time I checked, dmd's inliner would give up as soon as it 
sees any type of loop, even the simplest while loop... then the 
unroller and optimiser later on have less to work with.


So I would expect it's the loop in `sumPairwise()` [0] or 
`sumKahan()` [1] that's the main source of your problems.


If we could get that to inline better using `dmd -inline` it 
would probably speed up quite a lot of code.


[0] 
https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L5483
[1] 
https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L5578


Re: Phobos begat madness

2018-06-24 Thread David Bennett via Digitalmars-d

On Friday, 22 June 2018 at 21:37:07 UTC, Walter Bright wrote:


If someone wants to figure out how to build an uncomplicated, 
straightforward, efficient implementation of text() that we can 
be proud of, that would be a nice contribution.


Here [0] is part of a benchmark for implementing `to!string` with 
the lower level api design I was talking about in my other post 
[1].


On my machine i get these results:

$ dmd -dip1000
to!(string):17 secs, 88 ms, 322 μs, and 1 hnsec
newTo!(string): 8 secs, 785 ms, 325 μs, and 1 hnsec
@nogc writeCharsTo: 4 secs, 404 ms, 21 μs, and 7 hnsecs

$ dmd -dip1000 -O -release -inline
to!(string):9 secs, 396 ms, 688 μs, and 1 hnsec
newTo!(string): 4 secs, 640 ms, and 698 μs
@nogc writeCharsTo: 1 sec, 288 ms, 176 μs, and 9 hnsecs

$ ldc2 -dip1000 -O3 -release
to!(string):4 secs, 489 ms, 52 μs, and 3 hnsecs
newTo!(string): 3 secs, 781 ms, 990 μs, and 5 hnsecs
@nogc writeCharsTo: 752 ms, 989 μs, and 5 hnsecs

I will upload the benchmark for `text` tonight.

Also other points to make are:
   Using this low level api will work in -betterC code.
   It might even fit into utiliD [2].

[0] 
https://run.dlang.io/gist/97639a90931ad8e6e3a1ea564c46d710?args=-O%20-release%20-inline%20-dip1000
[1] 
https://forum.dlang.org/post/erxtrmnqbcbtgokou...@forum.dlang.org

[2] https://github.com/JinShil/utiliD



Re: Phobos begat madness

2018-06-24 Thread David Bennett via Digitalmars-d
On Saturday, 23 June 2018 at 20:17:01 UTC, Vladimir Panteleev 
wrote:

On Friday, 22 June 2018 at 21:37:07 UTC, Walter Bright wrote:

  text
  begat textImpl
  begat to
  begat toImpl
  begat toStr
  begat formatValue
  begat formatValueImpl
  begat put
  begat doPut
  begat Appender.put
  begat Appender.put


Hmm, this looks suboptimal for more than one reason. Wouldn't 
`text` benefit from using an appender in its implementation, 
rather than letting every invocation of `to` have its own? I.e. 
there ought to be one Appender per `text` invocation, rather 
than per one `text` argument.


textImpl seems to already have a branch for >1 arguments, but 
it still invokes to!S(arg) for them.


`text` has an appender [0] but it calls `to!` for every 
non-integer, so it has effectively O(n+1) GC allocations. We 
should be able to get this down to O(1).


The initially obvious way to do this would be allowing `to!` to 
take an `OutputRange`... but this would not improve the OP issue 
Walter's had with trying to trace template expansions. (in fact 
it would make it worse and add a lot of template bloat)


So my idea is to have a lower level API that is `@safe @nogc pure 
nothrow`, takes already allocated memory and writes to it like:


---
// Reterning W[] here with a slice of the original buffer so you 
can use it in tests easily.
@safe @nogc pure nothrow W[] writeCharsTo(T, W)(T input, scope 
W[] buffer);

---

This could then be used in both `to!` and `text`, or directly if 
the user wanted a @nogc option (ie json generator, or use with 
std.io etc).


I've done some benchmarks with integers and `to!` becomes almost 
twice as fast with `dmd -O -release -inline` and still ~30% 
faster with `ldc2 -O3 -release` (as its zero copy unlike the 
current `toChars` InputRange which copies when used in `to!`)


Early results of a `text` benchmark show even better speed 
improvements.


I will clean up the benchmark code I have and post it for you to 
see tonight.


In principle would this type of addition be accepted into phobos?

Thanks,
David

[0] https://github.com/dlang/phobos/blob/master/std/conv.d#L4243


Re: Phobos begat madness

2018-06-24 Thread David Bennett via Digitalmars-d

On Friday, 22 June 2018 at 22:36:23 UTC, Adam D. Ruppe wrote:
I can't for at last two weeks, I'm about to fly tomorrow... and 
I'm getting married in August too so my life is kinda hectic.


Congrats!


Re: Class qualifier vs struct qualifier

2018-06-15 Thread David Bennett via Digitalmars-d-learn

On Wednesday, 13 June 2018 at 07:35:25 UTC, RazvanN wrote:

Hello,

I'm having a hard time understanding whether this inconsistency 
is a bug or intended behavior:


immutable class Foo {}
immutable struct Bar {}

void main()
{
import std.stdio : writeln;
Foo a;
Bar b;

writeln("typeof(a): ", typeof(a).stringof);
writeln("typeof(b): ", typeof(b).stringof);
}

prints:

typeof(Foo): Foo
typeof(Bar): immutable(Bar)


It seems like the class storage class is not taken into account 
which leads to some awkward situations like:


immutable class Foo
{
this() {}
}

void main()
{
Foo a = new Foo(); // error: immutable method `this` is not 
callable using a

   // mutable object
}

To make it work I have to add immutable to both sides of the 
expression : immutable Foo a = new immutable Foo(); this is a 
wonder of redundancy. I already declared the class as immutable 
so it shouldn't be possible to have mutable instances of it 
(and it isn't), however I am forced to write the immutable 
twice even though it is pretty obvious that the class cannot be 
mutated.


Just tested and I only seem to need to add the immutable to the 
left of the expression.


https://run.dlang.io/is/EZ7es0

Also with the struct `Bar* b = new Bar();` works fine so i guess 
the discrepancy is because the class ref is mutatable.


Re: Confusion/trying to understand CTFE keywords

2018-06-07 Thread David Bennett via Digitalmars-d-learn

On Thursday, 7 June 2018 at 04:58:40 UTC, Jonathan M Davis wrote:


It would be trivial enough to create a wrapper template so that 
you can do something like


immutable n = ctfe!(foo());

e.g.

template ctfe(alias value)
{
enum ctfe = value;
}



Would this be equivalent to using static immutable?

static immutable n = foo();

In this case both the compiletime and runtime values were 
calculated using cfte.


Also back to the OP the way I think of enum, static types is like 
this:


alias and enum create compiletime stuff from compiletime stuff.
static creates runtime stuff from compiletime stuff.

Is that view valid in most cases?




Re: stride in slices

2018-06-05 Thread David Bennett via Digitalmars-d

On Tuesday, 5 June 2018 at 05:05:47 UTC, David Bennett wrote:

On Tuesday, 5 June 2018 at 03:13:05 UTC, Meta wrote:


14 ms, 520 μs, and 4 hnsecs
13 ms, 87 μs, and 2 hnsecs
12 ms, 938 μs, and 8 hnsecs


When using `dmd -inline -O -release` with an extra simd 
benchmark I get:


for loop:21 ms, 291 μs, and 6 hnsecs
stride/fill: 64 ms, 927 μs, and 9 hnsecs
stride/each: 52 ms, 740 μs, and 8 hnsecs
simd &=: 6 ms, 900 μs, and 8 hnsecs

https://run.dlang.io/gist/5fe73cbf9943aa57be1101e597bb25e4?args=-inline%20-O%20-release

Though the simd version does not work in ldc...


Here's a version that works in ldc:

https://run.dlang.io/gist/1d4bb542427fb82cc455fe9dc30185d7?compiler=ldc=-inline%20-O4%20-release

for loop:16 ms, 594 μs, and 1 hnsec
stride/fill: 14 ms, 918 μs, and 9 hnsecs
stride/each: 14 ms and 813 μs
simd &=: 7 ms, 153 μs, and 6 hnsecs



Re: stride in slices

2018-06-04 Thread David Bennett via Digitalmars-d

On Tuesday, 5 June 2018 at 03:13:05 UTC, Meta wrote:


14 ms, 520 μs, and 4 hnsecs
13 ms, 87 μs, and 2 hnsecs
12 ms, 938 μs, and 8 hnsecs


When using `dmd -inline -O -release` with an extra simd benchmark 
I get:


for loop:21 ms, 291 μs, and 6 hnsecs
stride/fill: 64 ms, 927 μs, and 9 hnsecs
stride/each: 52 ms, 740 μs, and 8 hnsecs
simd &=: 6 ms, 900 μs, and 8 hnsecs

https://run.dlang.io/gist/5fe73cbf9943aa57be1101e597bb25e4?args=-inline%20-O%20-release

Though the simd version does not work in ldc...


Re: cycle dependencies

2018-05-31 Thread David Bennett via Digitalmars-d
On Thursday, 31 May 2018 at 15:15:44 UTC, Steven Schveighoffer 
wrote:

On 5/31/18 2:14 AM, Simen Kjærås wrote:
On Wednesday, 30 May 2018 at 20:57:32 UTC, DigitalDesigns 
wrote:
Why is this a runtime issue? It is not as if the execution of 
static this are non-deterministic. The compiler and linker 
must order the calls in some way.


Because of separate compilation, the compiler can't do it. 
Because the generic linker doesn't do that sort of thing, the 
linker can't do it.


The first part is essentially intractable - e.g. module A's 
static this uses a global variable in module B that's set by 
module C. Module A may be compiled separately from module C, 
so the compiler can't see the dependency.


Yes, this is really the crux of it.

I want to stress that the cycle detection is not really for the 
sake of detecting cycles, it's because you need to sort the 
modules in the order their static ctors should be called. When 
you can't sort them in an order, you have to call them in an 
arbitrary order (probably just in the order they were linked).


It is really a shame we have to do this at runtime, but that's 
due to the compilation model we are stuck with, and the linker 
tools we deal with.




Thinking about this problem for a while I can up with something 
that could both reduce the work the runtime had to do and allow 
us to remove the error in the OP.


But now I see most of it was suggested in that pull request. [1]

Would the best way to implement this be to extend ModuleInfo and 
include a getter that   loads the dependencies like 
importedModules(), or should the ctor/dtor stuff be moved to a 
new tables?


Also we might be able to get the compiler to insert a 
cluster_hash that's unique for each compiler run and a 
pre-ordered cluster_index. Then use this to speed up sorting in 
the runtime.


[1] 
https://github.com/dlang/druntime/pull/1602#issuecomment-231527759


Re: What are AST Macros?

2018-04-13 Thread David Bennett via Digitalmars-d

On Friday, 13 April 2018 at 11:54:12 UTC, David Bennett wrote:
Also the other idea I had was to have mixin functions that only 
take compiletime args (they are UFCS-able though, unlike 
templates) and mixin themselves when called like:


---
mixin add1Xtimes(alias int a, alias int t){
uint i=t;
do{a++;}while(--i);
return a;
}
@safe unittest{
uint n=0;
n.add1Xtimes!(4).add1Xtimes!(6);
assert(n==10);
}
---

[snip]

I haven't really given much thought to the implementation of 
this though.


With more thought thats probably not a good solution as its 
different from the rest of the language and would be harder then 
it needs to be in order to integrate with the front-end.


What could work though is having a new AutoMixinDecloration that 
was inited with an expression. This expression would contain a 
call chain to regular functions, templates, other 
AutoMixinDecloration etc. Then when it's called it dups the 
contents of these functions into the callers scope.


---
auto ref incXTimesAndCount(string cident, alias uint csym, uint 
times)(auto ref uint a=0){

uint t = times;
do{
mixin(cident~"++;");
csym++;
a++;
}while(--t);
return a;
}

auto mixin incXAndXTimesAndCount(string cident, alias uint csym, 
uint t1, uint t2)
= incXTimesAndCount!(cident, csym, 
t1).incXTimesAndCount!(cident, csym, t2);


@safe unittest{
uint n=10;
uint c1=0;
uint c2=0;
uint r = n.incXAndXTimesAndCount!("c1", c2, 4, 6);
assert(n==20);
assert(c1==10);
assert(c2==10);
assert(r==20);
}
---

And it lowers to this in the front end:

---
@safe unittest{
uint n=10;
uint c1=0;
uint c2=0;
uint __m0_t=4;
do{n++; c1++; c2++;}while(--__m0_t);
uint __m1_t=6;
do{n++; c1++; c2++;}while(--__m1_t);
uint r = n;
assert(n==20);
assert(c1==10);
assert(c2==10);
assert(r==20);
}
---

Or it might be even possible to make the current 
TemplateMixinDeclaration to act like this if you add the auto 
keyword to the declaration with a symbol with the same name in 
the scope and the above was just sugar to this:


---
auto mixin template incXAndXTimesAndCount(string cident, alias 
uint csym, uint t1, uint t2)

{
alias incXAndXTimesAndCount
= incXTimesAndCount!(cident, csym, 
t1).incXTimesAndCount!(cident, csym, t2);

}
---


Re: What are AST Macros?

2018-04-13 Thread David Bennett via Digitalmars-d

On Friday, 6 April 2018 at 20:33:10 UTC, Chris Katko wrote:
Sorry if this is "re-opening" an old thread, but did anything 
come from this and DIP50? It seems like a really interesting 
concept and this thread was one of the first results for a 
Google search.


Thanks.


Thanks for reminding me about this thread, I thought I would see 
how close i could get to having this work now that I know D's 
edges better:


On Sunday, 11 July 2010 at 13:29:36 UTC, Michel Fortin wrote:


That said, I don't feel like I'm cheating when using string 
mixins. I find them a quite good substitute to AST macros. And 
perhaps string mixins are simpler too: you don't have to learn 
a new macro syntax, you just manipulate strings. Though I'm 
still waiting for the day we can use string mixins in 
expressions to do things like this:


int num = 1;
string result = substitute!"Number: $num";
assert(result == "Number: 1");


So what i came up with was:

--- substituter.d
module substituter;

string substituteForMixin(string input){

input ~= ` `;
string output = ``;
size_t l= input.length-1;

for(size_t i=0; i

Re: Is sorted using SIMD instructions

2018-04-12 Thread David Bennett via Digitalmars-d
On Thursday, 12 April 2018 at 10:14:55 UTC, rikki cattermole 
wrote:


Just checked, change int to float and it uses ucomiss (SIMD, 
ldc -O3).


There may not be an instruction for int's.


Yep logic is much easier with floats and is available on SSE.

It's hard to do logic on ints until SSE4.1 as theres no easy way 
to jump.
(With SSE I think it would require putting the result on the 
stack and checking it for zeros using 64bit regs)


Even with SSE4.1 it requires at lest one extra instruction as 
only PTEST sets flags.


That said, is it possible to get the result of PTEST as a bool 
using core.simd? I was wondering if it would be possible write 
the example using that.


Normally I just write simple functions like this in yasm and link 
them in extern(C).


Re: Migrating an existing more modern GC to D's gc.d

2018-04-12 Thread David Bennett via Digitalmars-d
On Wednesday, 11 April 2018 at 19:38:59 UTC, Dmitry Olshansky 
wrote:

On Tuesday, 10 April 2018 at 07:22:14 UTC, David Bennett wrote:
People cast from thread local to shared? ...okay thats no 
fun...  :(


I can understand the other way, thats why i was leaning on the 
conservative side and putting more stuff in the global pools.


Well you might want to build something as thread-local and then 
publish as shared.


Yeah I can see if your trying to share types like classes, shared 
would get in the way quite quick.


I think it could be __to_shared(ptr, length) to let GC know 
that block should be added to global set of sorts. That will 
foobar the GC design quite a bit but to have per thread GCs I’d 
take that risk.


Yeah I had this idea also, the runtime gets a hook on 
cast(shared) and the GC then just sets a flag and that part of 
memory will never be freed inside a thread-local mark/sweep. No 
move needed.


But then keeping in mind transitive nature of shared Maybe 
not ;)


Yeah shared is quite locked down so should have less ways people 
could foil my plans.


It's __gshared that im worried about now, ie if you had a class 
(stored in global pool) that you then assigned a local class to 
one of it's members. When a thread-local mark/sweep happened it 
wouldn't see the ref in the global pool and the member might get 
removed...


---
class A{}

class B{
__gshared A a;
this(A a){
this.a=a;
}
}

void main()
{
A a = new A();
B b = new B(a);
}
---

Currently my idea of storing classes with __gshared members would 
put B on the global poll but theres no cast so A would not be 
hoocked with __to_shared(). I guess the compiler could in theory 
inject the same __to_shared() in this case also, but it would be 
a lot harder and would probably be a mess as theres no cast to 
hook.


So maybe with __gshared it should be on the thread-local pool but 
marked as global.. but you might be able to mix shared and 
__gshared in a way that wouldn't work.


Maybe it should work the other way around - keep all in global 
pool, and have per-thread ref-sets of some form. Tricky anyway.


Would be worth some thought, I'll keep it in mind.

For now, I'm seeing if I can just make it so each thread has it's 
own Bin list, this way the data is stored in a way where the 
thread-local stuff is generally packed closer together and theres 
a higher chance to have a whole free page after a global 
mark/sweep.


If there a good benchmark for the GC I can run to see if I'm 
actually improving things?


Re: Migrating an existing more modern GC to D's gc.d

2018-04-10 Thread David Bennett via Digitalmars-d

On Tuesday, 10 April 2018 at 08:10:32 UTC, Jonathan M Davis wrote:


Yes. They expect it to work, and as the language is currently 
designed, it works perfectly well. In fact, it's even built 
into the language. e.g.


int[] foo() pure
{
return [1, 2, 3, 4];
}

void main()
{
immutable arr = foo();
}

compiles thanks to the fact that the compiler can guarantee 
from the signature of foo that its return value is unique.




Oh is that run at runtime? I thought D was just smart and did it 
using CTFE.




We also have std.exception.assumeUnique (which is just a cast 
to immutable) as a way to document that you're guaranteeing 
that a reference to an object is unique and therefore can be 
safely cast to immutable.




Can't say I've used std.exception.assumeUnique, but I guess other 
people have a use for it as it exists.


Would be nice if you could inject type checking information at 
compile time without effecting the storage class. But thats a bit 
OT now.




Because of how restrictive shared and immutable are, you 
frequently have to build them from thread-local, mutable data. 
And while it's preferable to have as little in your program be 
shared as possible and to favor solutions such as doing message 
passing with std.concurrency, there are situations where you 
pretty much need to have complex shared objects. And since D is 
a systems language, we're a lot more restricted in the 
assumptions that we can make in comparison to a language such 
as Java or C#.




Yeah i agree that any solution should keep in mind that D is a 
systems language and should allow you to do stuff when you need 
to.


Oh, I just had a much simpler idea that shouldn't have any 
issues, I'll see if that makes the GC faster to allocate. 
(everything else is the same)


Re: Migrating an existing more modern GC to D's gc.d

2018-04-10 Thread David Bennett via Digitalmars-d

On Tuesday, 10 April 2018 at 06:47:53 UTC, Jonathan M Davis wrote:
As it stands, it's impossible to have thread-local memory 
pools. It's quite legal to construct an object as shared or 
thread-local and cast it to the other. In fact, it's _highly_ 
likely that that's how any shared object of any complexity is 
going to be constructed. Similarly, it's extremely common to 
allocate an object as mutable and then cast it to immutable 
(either using assumeUnique or by using a pure function where 
the compiler does the cast implicitly for you if it can 
guarantee that the return value is unique), and immutable 
objects are implicitly shared.




(Honest question:) Do people really cast from local to 
shared/immutable and expect it to work?
(when ever I cast something more complex then a size_t I almost 
expect it to blow up... or break sometime in the future)


That said, I can understanding building a shared object from 
parts of local data... though I try to keep my thread barriers as 
thin as possible myself. (meaning I tend to copy stuff to the 
shared and have as few shared's as possible)




At minimum, there would have to be runtime hooks to do 
something like move an object between pools when it is cast to 
shared or immutable (or back) in order to ensure that an object 
was in the right pool, but if that requires copying the object 
rather than just moving the memory block, then it can't be 
done, because every pointer or reference pointing to that 
object would have to be rewritten (which isn't supported by the 
language).




A hook for local to cast(shared) could work... but would require 
a DIP I guess. I was hoping to make a more incremental 
improvement the the GC.




Also, it would be a disaster for shared, because the typical 
way to use shared is to protect the shared object with a mutex, 
cast away shared so that it can be operated on as thread-local 
within that section of code, and then before the mutex is 
released, all thread-local references then need to be gone. e.g.



synchronized(mutex)
{
auto threadLocal = cast(MyType)mySharedObject;

// do something with threadLocal...

// threadLocal leaves scope and is gone without being cast 
back

}

// all references to the shared object should now be shared



Yeah thats why I was still scanning all thread stacks and pages 
when marking global data.

So a shared -> local is a no op but the other way needs thought.



You really _don't_ want the shared object to move between pools
because of that cast (since it would hurt performance), and in 
such a
situation, you don't usually cast back to shared. Rather, you 
have a shared
reference, cast it to get a thread-local reference, and then 
let the
thread-local reference leave scope. So, the same object 
temporarily has both
a thread-local and a shared reference to it, and if it were 
moved to the
thread-local pool with the cast, it would never be moved back 
when the

thread-local references left scope and the mutex was released.

Having synchronized classes as described in TDPL would make the 
above code cleaner in the cases where a synchronized class 
would work, but the basic concept is the same. It would still 
be doing a cast underneath the hood, and it would still have 
the same problems. It just wouldn't involve explicit casting. 
shared's design inherently requires casting away shared, so it 
just plain isn't going to play well with anything that doesn't 
play well with such casts - such as having thread-local heaps.




I would think a shared class would never be marked as a 
THREAD_LOCAL as it has a shared member.




Also, IIRC, at one point, Daniel Murphy explained to me some 
problem with classes with regards to the virtual table or the 
TypeInfo that inherently wouldn't work with trying to move it 
between threads. Unfortunately, I don't remember the details 
now, but I do remember that there's _something_ there that 
wouldn't work with thread-local heaps. And if anyone were to 
seriously try it, I expect that he could probably come up with 
the reasons again.


Regardless, I think that it's clear that in order to do 
anything with thread-local pools, we'd have to lock down the 
type system even further to disallow casts to or from shared or 
immutable, and that would really be a big problem given the 
inherent restrictions on those types and how shared is intended 
to be used. So, while it's a common idea as to how the GC could 
be improved, and it would be great if we could do it, I think 
that it goes right along with all of the other ideas that 
require stuff like read and write barriers everywhere and thus 
will never be in D's GC.


- Jonathan M Davis


Yeah I thought it would have issues, thanks for your feedback!

I'll see if I can come up with a better idea that doesn't break 
as much stuff.


Re: Migrating an existing more modern GC to D's gc.d

2018-04-10 Thread David Bennett via Digitalmars-d

On Tuesday, 10 April 2018 at 06:43:28 UTC, Dmitry Olshansky wrote:

On Tuesday, 10 April 2018 at 06:10:10 UTC, David Bennett wrote:
I was thinking about messing with the GC in my free time just 
yesterday... how hard would it be:


[snip]


Lost immutable and that thread-local is often casted to 
immutable, sometimes by compiler.

See assumeUnique and its ilk in Phobos.

Same with shared - it’s still often the case that you allocate 
thread-local then cast to shared.


People cast from thread local to shared? ...okay thats no fun...  
:(


I can understand the other way, thats why i was leaning on the 
conservative side and putting more stuff in the global pools.




Lastly - thanks to 0-typesafety of delegates it’s trivial to 
share a single GC-backed stack with multiple threads. So what 
you deemed thread-local might be used in other thread, 
transitively so.


Oh thats a good point I didn't think of!



D is thread-local except when it’s not.



If thats possible we could also Just(TM) scan the current 
thread stack and mark/sweep only those pages. (without a stop 
the world)




That is indeed something we should at some point have. Needs 
cooperation from the language such as explicit functions for 
shared<->local conversions that run-time is aware of.




So the language could (in theory) inject a __move_to_global(ref 
local, ref global) when casting to shared and the GC would need 
to update all the references in the local pages to point to the 
new global address?


And when a thread ends we could give the pages to the global 
pool without a mark/sweep.


The idea is it works like it does currently unless something 
is invisible to other threads, Or am i missing something 
obvious? (quite likely)


Indeed there are ugly details that while would allow per thread 
GC in principle will in general crash and burn on most 
non-trivial programs.


Okay, thanks for the points they were very clear so I assume you 
have spent a lot more brain power on this then I have.


Re: Migrating an existing more modern GC to D's gc.d

2018-04-10 Thread David Bennett via Digitalmars-d

On Tuesday, 10 April 2018 at 06:10:10 UTC, David Bennett wrote:
I was thinking about messing with the GC in my free time just 
yesterday... how hard would it be:


[snip]

The idea is it works like it does currently unless something is 
invisible to other threads, Or am i missing something obvious? 
(quite likely)


Forgot to mention that a non-thread local mark/sweep would still 
scan all thread stacks and pages like it does currently as a 
thread local could hold a pointer the the global data (ie a copy 
of __gshared, void*).


The only why I can think of to break this idea is using cast() or 
sending something to a C function that then does and adds 
pointers in global data to the thread local stuff...


Re: Migrating an existing more modern GC to D's gc.d

2018-04-10 Thread David Bennett via Digitalmars-d

On Tuesday, 10 April 2018 at 05:26:28 UTC, Dmitry Olshansky wrote:

On Monday, 9 April 2018 at 19:50:16 UTC, H. S. Teoh wrote:

Last I remembered, you were working on a GC prototype for D?


Still there, but my spare time is super limited lately, the 
other project preempted that for the moment.



Any news on that, or have you basically given it up?


Might try to hack to the finish line in one good night, it was 
pretty close to complete. Debugging would be fun though ;)


I was thinking about messing with the GC in my free time just 
yesterday... how hard would it be:


Add a BlkAttr.THREAD_LOCAL, and set it from the runtime if the 
type or it's members are not shared or __gshared.


Then we could store BlkAttr.THREAD_LOCAL memory in different 
pages (per thread) without having to setting a mutex. (if we need 
to get new page from the global pool we set a mutex for that)


If thats possible we could also Just(TM) scan the current thread 
stack and mark/sweep only those pages. (without a stop the world)


And when a thread ends we could give the pages to the global pool 
without a mark/sweep.


The idea is it works like it does currently unless something is 
invisible to other threads, Or am i missing something obvious? 
(quite likely)


Re: Manipulate slice or specific element of range and return range

2018-03-22 Thread David Bennett via Digitalmars-d-learn

On Thursday, 22 March 2018 at 04:49:39 UTC, Seb wrote:


No need for regular expressions. D is powerful enough without 
them:


```
alias lowercased = (m, n) => 
m.take(n).asLowerCase.chain(m.drop(n));

```

https://run.dlang.io/is/cSL0si


And with the filter, so it passes the assert:

```
string input = "My Capital String";
auto lower1 = 
input.take(1).asLowerCase.chain(input.drop(1).filter!(c => c != ' 
')).array;

assert(lower1 == "myCapitalString");
```

Also a few more options (including a slice version):

https://run.dlang.io/is/dZHcSo

As the input is never read until the array() is run, each element 
in the array should only be copied from RAM to the stack once.


And if you compile with LDC a lot of it can be inlined and the 
stack copies of the range structs and elements should be 
minimised even further.


Re: How to check if string is available at compile time

2017-09-21 Thread David Bennett via Digitalmars-d-learn

On Thursday, 21 September 2017 at 13:52:25 UTC, Meta wrote:
On Thursday, 21 September 2017 at 12:30:15 UTC, David Bennett 
wrote:
On Thursday, 21 September 2017 at 11:42:36 UTC, David Bennett 
wrote:


enum isCTstring(alias arg) = (!isAssignable!(typeof(arg)) || 
__traits(compiles, mixin(` "foo" ~ `~__traits(identifier, 
arg;


[snip]

But this seems quite hackish... any better ideas?


Try __traits(compiles, { enum _ = arg; }). Creating an enum 
necessarily requires that its value is available at compile 
time.


Ahh, warping it in {} seems to change the timing of the 
execution, this is starting to make a lot of sense to me now. 
(also explains why int[arg] works).


Thats much cleaner and I'll use that from now on.

Thanks a lot!
David


Re: How to check if string is available at compile time

2017-09-21 Thread David Bennett via Digitalmars-d-learn
On Thursday, 21 September 2017 at 11:42:36 UTC, David Bennett 
wrote:

[snip]

```
string[] escapeCTFE(Args...)(){

static foreach (arg; Args){
static if(__traits(compiles, ###WHATDOIPUTHERE###)){
[snip]



So far the best I've come up with is :

```

enum isCTstring(alias arg) = (!isAssignable!(typeof(arg)) || 
__traits(compiles, mixin(` "foo" ~ `~__traits(identifier, arg;


string[] escapeCTFE(Args...)(){

static foreach (arg; Args){
static if(isCTstring!(arg)){
pragma(msg, "Do work on string: ", arg);
}else{
pragma(msg, __traits(identifier, arg), " can only be 
read at runtime");

}
}
return new string[32];
}

```

But this seems quite hackish... any better ideas?


How to check if string is available at compile time

2017-09-21 Thread David Bennett via Digitalmars-d-learn

Hi Guys,

Is there an easy way to check if the value of string passed to a 
template is available at compile time?


Here is a cut down example of that I'm doing:

```
string[] escapeCTFE(Args...)(){

static foreach (arg; Args){
static if(__traits(compiles, ###WHATDOIPUTHERE###)){
pragma(msg, "Do work on string: ", arg);
}else{
pragma(msg, __traits(identifier, arg), " can only be 
read at runtime");

}
}

}

void main(){

string a = "a";
static string b = "b";
enum string c = "c";
immutable string d = "d";
const string e = "e";

enum escape_as_much_as_possible = escapeCTFE!(a,b,c,d,e,"f");
}

```

I know for ints I can use __traits(compiles, int[arg]) but I'm 
not sure about strings.


I believe only a and b should be hidden from pragma right?

Thanks,
David.


Re: Internal error mixing templates and CTFE

2017-09-17 Thread David Bennett via Digitalmars-d-learn

On Friday, 15 September 2017 at 15:48:10 UTC, Stefan Koch wrote:

are you using ucent ?


Not that I know of, the code above is the full code (not sure 
what's used internally for string literals).


I was using dmd 2.076 from the apt repo but the error also 
happens in LDC 1.3[1].


Is there an easy way for me to test newCTFE?

The reduced version to get the same error is:

```
struct Content{string[] parts;}

void main(){
enum Content content = {};
content.parts ~= "";
}
```

Strange (for a CTFE noob like me anyway) thing is the following 
code produces no error or warning. (obviously it doesn't do what 
it looks like it does)


```
struct Content{
string[] parts;
void add(string s)(){
parts ~= "Part: "~s;
}
}

void main(){
enum Content content = {};
content.add!("Header")();
}
```

I would have thought both the code in the OP and the above two 
codes should produce a warning pointing out that using a compile 
time value like that has no useful effect. As this would be 
useful information for noobs like me...


Actually now that I think about it there could be a "valid" use.. 
ie if the add function set global state... does this even work... 
(checks) ... yes it does... so I guess a warning cant really 
happen then.



[1] Here is the LDC backtrace:

ldc2: /build/ldc-6CClyQ/ldc-1.3.0/gen/dvalue.cpp:43: llvm::Value* 
DtoLVal(DValue*): Assertion `lval' failed.
#0 0x7f1d568658a8 
llvm::sys::PrintStackTrace(llvm::raw_ostream&) 
(/usr/lib/x86_64-linux-gnu/libLLVM-4.0.so.1+0x76e8a8)
#1 0x7f1d56863786 llvm::sys::RunSignalHandlers() 
(/usr/lib/x86_64-linux-gnu/libLLVM-4.0.so.1+0x76c786)
#2 0x7f1d568638e5 
(/usr/lib/x86_64-linux-gnu/libLLVM-4.0.so.1+0x76c8e5)
#3 0x7f1d55ce2670 __restore_rt 
(/lib/x86_64-linux-gnu/libpthread.so.0+0x11670)
#4 0x7f1d5509977f gsignal 
/build/glibc-mXZSwJ/glibc-2.24/signal/../sysdeps/unix/sysv/linux/raise.c:58:0
#5 0x7f1d5509b37a abort 
/build/glibc-mXZSwJ/glibc-2.24/stdlib/abort.c:91:0
#6 0x7f1d55091b47 __assert_fail_base 
/build/glibc-mXZSwJ/glibc-2.24/assert/assert.c:92:0

#7 0x7f1d55091bf2 (/lib/x86_64-linux-gnu/libc.so.6+0x2dbf2)
#8 0x5644df8d2310 (ldc2+0x3cb310)
...
#25 0x5644df909370 (ldc2+0x402370)
#26 0x7f1d550843f1 __libc_start_main 
/build/glibc-mXZSwJ/glibc-2.24/csu/../csu/libc-start.c:325:0

#27 0x5644df6538ea (ldc2+0x14c8ea)
Aborted (core dumped)
ldc2 failed with exit code 134.




Re: Internal error mixing templates and CTFE

2017-09-15 Thread David Bennett via Digitalmars-d-learn
On Friday, 15 September 2017 at 07:12:36 UTC, Andrea Fontana 
wrote:

Internal error is always a bug, so it should be reported!


I have opened a issue: 
https://issues.dlang.org/show_bug.cgi?id=17828


Internal error mixing templates and CTFE

2017-09-15 Thread David Bennett via Digitalmars-d-learn

Hi Guys,

I've been playing around with CTFE today to see how far I would 
push it but I'm having an issue appending to an array on a struct 
in CTFE from a template:


```
struct Content{
string[] parts;
}

void add_part_to_content(Content content, string s)(){
content.parts ~= "Part: "~s;
}

void main(){
enum Content content = {};
add_part_to_content!(content, "Header")();
}
```

This generates the following output:

& el:0x24052a0 cnt=0 cs=0 &  TY* 0x2403100
 el:0x2403100 cnt=0 cs=0 const  TYucent 0LL+0LL
Internal error: ddmd/backend/cgcs.c 352

FYI: I also get the same error with the template 
add_part_to_content(alias Content content, alias s) syntax.


So two questions:

Should what I'm doing be possible?

Is this an error in dmd, and should I open a bug report?