Re: A path commonPrefix function

2020-01-04 Thread cblake
`result += mid + 1 - lo` is, indeed, way cheaper than `result.add`, but that 
binary search approach only does the `result.add` about `ceil(log_2(minLen))` 
times (i.e., like 3-10 times probably). I couldn't even measure the difference 
on my 3078 entry average total length 17 `/usr/bin/\*` example (i.e. noise was 
>> difference).

Regardless, I **100% agree** that separating into a prefixLen and then getting 
that slice would be a nicer factoring anyway. The caller may only need to test 
the length against `0` or something.

Another algorithm of interest in terms of this whole thread is the "just 
compare first & last in sorted order" approach. This very "tidy" from both a 
conceptual and coding point of view: 


proc range*[T](xs: openArray[T]): tuple[min, max: T] =
  if xs.len < 1: return   # default vals for T
  result.min = xs[0]
  result.max = xs[0]
  for x in xs:
result.min = min(result.min, x)
result.max = max(result.max, x)

proc longestCommonPrefixLen*(strs: openArray[string]): int =
  let (min, max) = strs.range
  for i, c in min:
if c != max[i]: return i
  return min.len


Run

As written, that's about 6x slower than the binary search approach for L2 
resident data. It's probably possible to really speed up `range` for 
`openArray[string]` with some shallow copies in the loop and a real copy at the 
end. That might be a fun exercise for someone.

Indeed, for very large inputs, bandwidth starvation of modern CPUs will mean 
that doing only one pass over said inputs is going to be best, even if it does 
quite a bit more CPU ALU-type work. So, even if that `range` cannot be sped up 
to match/beat the binary search in this context, one would still want to switch 
to this (or some other) one pass algo to accommodate giant inputs in a more 
general setting..probably past the L2 or L3 boundary (assuming it can run with 
minimal cache competition).

@marks did not really discuss the size of his inputs or his use case, though 
his second "faster on his test set" is notably a multi-pass algorithm.


Re: How to fix this type mismatch error ?

2020-01-04 Thread kcvinu
Hi all, i avoid the need of "addHandler" proc and now it seems working. But in 
an ugly style.


Re: How to write enum values without numbering order ?

2020-01-04 Thread kcvinu
Let me try it. Thank you.


Re: Docgen for macro generated code

2020-01-04 Thread disruptek
This package runs a macro and both consumes and renders the result to a file. 
It seems to do what you want; maybe it will inspire an even better solution:

[https://github.com/disruptek/openapi](https://github.com/disruptek/openapi)


Docgen for macro generated code

2020-01-04 Thread chrisheller
We have a bunch of Nim types/procs that get generated based on some external 
data. That all works well, including pulling in the doc comments when running 
nimdoc.

The main issue with the generated doc is that it is all in the same file as 
whatever module that runs the macro to load the external data. It would be nice 
to find a way to split this up.

For example if you generate typeA, typeB, typeC, etc. along with procs that 
work on those types, I would like to generate something like typea.html, 
typeb.html, typec.html. It doesn't appear possible to insert macro generated 
code into a separate module though. From glancing at the compiler code, modules 
seem like they have to come from files that exist somewhere in the filesystem.

One possibility that might work is to use toStrLit to write the macro generated 
code to temp files and then run nimdoc on the temp files.

Any other suggestions would be welcome.

Thanks


Re: How to fix this type mismatch error ?

2020-01-04 Thread kcvinu
Thanks for the reply. I tried with cast and it worked. But i dont want to use 
it anymore. Actually this code is a prototype to express my idea. I think its 
quite easy for you if i tell the real problem. This is for a gui library. Here 
is the details.

  1. I have a GUI type named "Form"
  2. A Form object has a list of "EventData"
  3. This is EventData




type
EventData* = ref object
msg * : UINT# this represent the window message
fnPtr* : FuncPtr# This is what i wrote in my above comment.
isProcSet : bool# A boolean flag


Run

Next, there so many types to use inside the function pointer. Here is a list 


type
EventArgs* = ref object of RootObj
MouseEventArgs* = ref object of EventArgs
KeyEventArgs* = ref object of EventArgs
PaintEventArgs* = ref object of EventArgs
#... And lot more


Run

Next, populating the event data list for Form object 


proc addHandler(me : Form, evt : UINT, pfn : FuncPtr ) =
var ed : EventData = new EventData
ed.msg = evt# messages like WM_PAINT etc
ed.fnPtr = pfn
ed.isProcSet = true


Run

> me.eventDataList.add(ed) # we put the event data to list

Next, this is happening inside my wndProc function 


case message
of WM_PAINT :
thisForm = getTheCurrentForm(hwnd)  # this will get the current Form 
object
evtData = thisForm.getEventData(message)  # this will get the event 
handler for current message
if evtData.isProcSet :
var pea : PaintEventArgs = newPaintEventArgs(wp, lp)  # We create a 
paint event args
procCall(evtData.fnPtr(thisForm, pea))  # this is our event handling
of WM_LBUTTONDOWN :
# same process for left button down


Run

So this is the total process. I am clueless now.


Re: How to fix this type mismatch error ?

2020-01-04 Thread Araq
(1) is the best approach IMO and can be hidden behind a macro/template, if you 
want to.


Re: How to write enum values without numbering order ?

2020-01-04 Thread Araq
> since i want to get "keys.A" style.

Keep it in its own module then and use `from keys import nil`.


Re: A path commonPrefix function

2020-01-04 Thread Araq
I would return an `int` instead of a string, much cheaper.


Re: How to fix this type mismatch error ?

2020-01-04 Thread doofenstein
I experienced this myself, unfortunately there's no "good" solution to this. 
Still I can think of three way to workaround this:

1\. the easiest way change the function: 


proc sampleProc(p : int, q : A) =
  let q = B(q)


Run

2\. wrap the function inside a closure 


p.setFuncPtr(proc(p: int, q: A) = sampleProc(q, B(q))


Run

This can also also be relegated to the register proc: 


proc setFuncPtr[T: A](me : Person, pfnPtr: proc(y: int, q: T)) =   # this 
proc will fetch the list
me.fnPtrList.add(proc(x: int, y: A) = pfnPtr(x, T(y)))


Run

3\. raw casts, I tried it once and it worked, but I wouldn't recommend it and I 
also don't even have the code around.


Re: Embedding libclang into Nim's compiler

2020-01-04 Thread Araq
I don't see the problem with shipping MingW with Nim on Windows and relying on 
the default C compiler on the other OSes. Cross-compilations in the age of CIs 
that then can actually **test** the produced binaries automatically is a 
non-issue.


How to fix this type mismatch error ?

2020-01-04 Thread kcvinu
Hi all, I have some code like this- 


type
A* = ref object of RootObj
#properties ...
B* = ref object of A
# properties  ...
FuncPtr* = proc(x : int, y : A)   # A function pointer aka delegate

Person* = ref object
fnPtrList* :  seq[FuncPtr]   # this list will init later
# props ...

proc setFuncPtr(me : Person, pfnPtr : FuncPtr) =   # this proc will fetch 
the list
me.fnPtrList.add(pfnPtr)



Run

Now, i want to create the person object 


proc sampleProc(p : int, q : B) # Here i am using B instead of A. Because i 
need it
var p = new Person
p.setFuncPtr(sampleProc) # This line is showing error. Compiler says it is 
expecting type "A" instead of B.



Run


Re: Embedding libclang into Nim's compiler

2020-01-04 Thread mratsim
> installing C/C++ cross compilers and cross linkers are painful on Windows

Developing on Windows is painful for everyone, dependency management is hell, 
everyone have to ship their dlls so you end up with dozens of zlib in the 
system, it's basically docker-land without the cool name. I don't think we can 
solve it, just look into the go instructions for windows "download this, 
uncompress there, add to your path". There is a reason why Microsoft added WSL.

Installing LLVM on windows is also painful.

However these are issues at the packaging level, it's not obvious that tightly 
coupling Nim compiler with a toolchain will make packaging any easier. And it 
comes with downsides that you highlighted as well.


Re: A path commonPrefix function

2020-01-04 Thread cblake
Eg., in Nim it might look like this: 


proc minLen(strs: openArray[string]): int =
  result = int.high
  for s in strs: result = min(result, s.len)

proc check(strs: openArray[string]; j0, j1: int): bool =
  let srcSlc = strs[0][j0..j1]
  for s in strs:
if s[j0..j1] != srcSlc: return false
  return true

proc longestCommonPfx*(strs: openArray[string]): string=
  if strs.len < 1: return ""
  let src = strs[0]
  if strs.len < 2: return src
  var lo = 0  # Binary search
  var hi = strs.minLen - 1
  while lo <= hi:
let mid = lo + (hi - lo) div 2
if check(strs, lo, mid):  # All strs match this
  result.add src[lo .. mid]   # Append to answer
  lo = mid + 1# Go higher
else: # Go lower
  hi = mid - 1

when isMainModule:
  import os
  echo longestCommonPfx(commandLineParams())


Run

There are also a lot of variants at 
[http://rosettacode.org/wiki/Longest_common_prefix](http://rosettacode.org/wiki/Longest_common_prefix)

For paths you would just need to add something to backup to the most recent 
directory separator, if any.


Re: A path commonPrefix function

2020-01-04 Thread cblake
Are you aware of this binary search approach? 
[https://www.tutorialcup.com/string/longest-common-prefix-using-biary-search.htm](https://www.tutorialcup.com/string/longest-common-prefix-using-biary-search.htm)


Re: A path commonPrefix function

2020-01-04 Thread marks
This is the fastest and best so far: 


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) == 0:
return ""
  let first = paths[0]
  var index = -1
  block loop:
for i in 0 ..< len(first):
  for j in 1 .. paths.high():
let path = paths[j]
if i < len(path) and first[i] != path[i]:
  break loop
  index = i
  if index == -1:
return ""
  else:
return first[0 .. first.rfind(sep, 0, index)]


Run


Re: A path commonPrefix function

2020-01-04 Thread marks
Thanks for that. I discovered that my new version is 4x faster than the 
original..


Re: Embedding libclang into Nim's compiler

2020-01-04 Thread LeFF
> Note that we already ship Nim with GCC on Windows. Mac OS already mostly 
> comes with clang and Linux also will have GCC/clang installed via a package 
> manager. Not sure there is much benefit in shipping this dependency on 
> Linux/Mac.

Yes, but installing C/C++ cross compilers and cross linkers are painful on 
Windows, it is easier on Linux, but still. And it is very nice to install one 
toolchain and target any supported OS/CPU without any troubles (Go, Zig and Red 
programming languages toolchains support it for example). 


Re: Embedding libclang into Nim's compiler

2020-01-04 Thread dom96
I've had a very similar idea and I actually have a pretty nice libclang wrapper 
which I've used for my C/C++ code obfuscator 
([https://picheta.me/obfuscator)](https://picheta.me/obfuscator\)). I've been 
meaning to open source it for a while now...

My idea differs in one important way though: there is no need for the compiler 
to depend on libclang as Nim's macros are already powerful enough to generate 
any wrappers that we might need. Instead we should use macros to call 
clang/libclang and generate the appropriate AST based on its output.

**All this being said though, as far as I know @shashlick has something like 
this already: https://github.com/nimterop/nimterop (but it uses tree-sitter 
instead of clang).**

> Self-contained toolchain by default (with cross compilation and cross 
> linking), without the need to install external C compilers (if the user wants 
> he could always use his own).

Note that we already ship Nim with GCC on Windows. Mac OS already mostly comes 
with clang and Linux also will have GCC/clang installed via a package manager. 
Not sure there is much benefit in shipping this dependency on Linux/Mac.


Re: A path commonPrefix function

2020-01-04 Thread cblake
> Is there a nim equivalent to Python's timeit module for timing snippets?

There are probably about 100 variants in people's local code, but I happened to 
just see your message and also to just add this to `cligen/osUt` the other day 
(needs `requires "cligen#head"` in your `.nimble` file or you could just copy 
this tiny impl and adapt as you like): 


import strutils, times

template timeIt*(label:string, unit:float, places=3, sep="\n", body: 
untyped) =
  let t0 = epochTime()
  body
  let dt = epochTime() - t0
  stdout.write label, " ", formatFloat(dt * unit, ffDecimal, places), sep

timeIt("write1", 1e6, 3, " ") : stderr.write "hi"
timeIt("write2", 1e6, 3, "\n"): stderr.write "there"


Run

You may want to add loops to repeat and use the `stats.RunningStat` stdlib API 
to do something nice more like Python's version. There is also this package 
called golden 
([https://github.com/disruptek/golden](https://github.com/disruptek/golden)) to 
try to iterate until timing noise has been suppressed. And probably other 
various solutions, too. (And sometimes noise **is** the data and you want 
cold-cache/system competition effects included...benchmarking is obviously a 
larger topic than a snippet thing.)


Embedding libclang into Nim's compiler

2020-01-04 Thread LeFF
Hello! Bare with me here. Recently I've been watching Zig programming language 
development streams. One of the thing that was very surprising to me is that 
Zig compiler embeds libclang and also minified versions of glibc, musl and 
mingw. That way Zig compiler can automatically import C code headers, without 
the need to write bindings and also compile and cross-compile C code being a 
self-contained toolchain (they use LLVM's cross-linker as far as I understood). 
I think this idea is very nice. Do you think it is a good idea to do the same 
for Nim compiler?

Pros:

  * Self-contained toolchain by default (with cross compilation and cross 
linking), without the need to install external C compilers (if the user wants 
he could always use his own).
  * Automatic imports of C/C++ headers, without the need to write bindings.
  * Potential compilation speed ups, if we compile to libclang AST directly, 
without preprocessing, parsing and compiling of generated C/C++ code.



Cons:

  * Quite some work should be done to bind libclang and integrate it with the 
current compiler.
  * The size of the current Nim compiler and the complexity of building it will 
somewhat increase. 




Re: How to write enum values without numbering order ?

2020-01-04 Thread kcvinu
Thanks. I decided manage with a normal object. Macros are out of my reach. And 
thanks for the suggestion but i can't use that style, since i want to get 
"keys.A" style. 


Re: A path commonPrefix function

2020-01-04 Thread marks
This version walks forward char by char. Is there a nim equivalent to Python's 
`timeit` module for timing snippets? 


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) == 0:
return ""
  result = paths[0]
  var index = 0
  var ok = false
  for path in paths[1 .. ^1]:
while index < len(path) and index < len(result) and
result[index] == path[index]:
  inc index
  ok = true
  result = if not ok:
  ""
  else:
result[0 .. result.rfind(sep, 0, index)]


Run