Re: A path commonPrefix function
`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 ?
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 ?
Let me try it. Thank you.
Re: Docgen for macro generated code
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
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 ?
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 ?
(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 ?
> 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
I would return an `int` instead of a string, much cheaper.
Re: How to fix this type mismatch error ?
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
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 ?
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
> 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
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
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
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
Thanks for that. I discovered that my new version is 4x faster than the original..
Re: Embedding libclang into Nim's compiler
> 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
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
> 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
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 ?
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
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