duangsuse::Echo
714 subscribers
4.24K photos
127 videos
583 files
6.46K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#windows #security #chrome #web Win8 无效, Win10 蓝屏重启
Forwarded from RWTG9Y4's STDOUT
好消息 好消息
现在你的 Chrome 可以直接造成系统 BSOD 啦
立刻在地址栏输入 \\.\globalroot\device\condrv\kernelconnect 领取蓝屏大礼包一份
* 就算是放在 <a href/> 里的链接也可以造成蓝屏
duangsuse::Echo
https://github.com/ice1000/arend-language-server/blob/88dd2e94ea7ae564a743d349b93487dd5aa4b5f8/src/main/kotlin/server.kt 草,原来冰封那么厉害也没有写自己的 Argument Parser... 我还以为函数式爱好者都痛恨 (org.apache.commons.cli) 需要 (opt as Options).addOption(Option.builder("i").build())…
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望
虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。

这里也有一个 initNewFrame + listen keyEvent & StringBuilder & draw text 的示例
总的来说是很重视性能的一个 JNI 封装, 利用了Critical Native ,从不在 Java/C++ 之间传输 primitive (array) 外的数据(这是十分推荐的);也会处理 String/std::string 缓存的问题(感觉管得有点宽,应该解耦了) 甚至可以自定义封送 转换函数
用了 intFlag @MagicConstant@Nullable 有好的 IDE 支持

看了一会想点 star ,突然发现我 GitHub 好像被 @ice1000 ban 了,现在还没有解除一样
可能是以前冒犯过他吧,觉得应该解除了啊,唉🌚
找了半天没找到他之前发的 JLine ,找到这个 ,代码质量……
duangsuse::Echo
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望 虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。 这里也有一个 initNewFrame + listen keyEvent & StringBuilder…
吃饭的路上(最近有点劳累过度了,思量着 ANSI BadApple 赶紧结束休息几天吧),谈到所谓“优雅性”,想了一下 ParserKt 新 LexerFeed 的问题,感觉很 complicated ,流对象的各种属性真的不好办

首先是说这个给冰封提到底有没有意义的问题(毕竟 PM 冰封是一个比较要心理准备的事情,心理难度比与 Python 红姐、九月姐 谈笑风生不低多少),最后结论是有。

虽然 jimgui 的本意未必是做“定义式”的 GUI 框架,更像是学习 JNI 设计,而且 Kotlin wrapper 很可能会有好的接口,技术交流也是不应有太多压力的。
TkGUI 的代码生成方法利用了 Python 无编译期/运行期,虚拟机相关组件基本可用的动态性,以及动态类型;很难(或者说意义不大)移植到 Java ,但我的本意是 GUI 可以这么写, ImGui 的做法可以说是业界惯例(就我的观察, GTK, Wx 的大部分封装不需要为子控件选择 parent, 但没有一个支持树形代码定义一个视图,即便其语言有足够表现力),Java 的 Swing Frame,Panel 和 Fx Stage,Scene,Group 都必须用 mutate 对象的方法「创建」模板化的视图树(当然这是过程式的自然映照,无可厚非), Qt 和 C#, VB 有 uic 这样的 code generator ;而 TkGUI 的 way 更像是 parser combinator 那样,尽可能少用外部工具,直接在语言里组合。

这个 way 就是一句话,“优美的代码能直观地反映它所处理数据的结构”,程序结构和数据结构相互照应、谐调统一,虽然会有额外开销,但一件事情只有你重视了才能找到各方面的最优解决办法,否则就永远只是传说。

再谈 ParserKt 的问题,其实最初版本相较于一些同类已经可以算是优雅了(当然离我想的还更远)
几个月前的重计划里包含了“削除 Parser 里 Lexer 相关代码”的改动,可以说是解决了我心头一厌(很多 PEG 生成器都逃不开跳空格注释的问题,要么然写文法里,要么然走 lexer/parser 的老路,要么然可配置性不够好,这是比较草的,因为我觉得在 a b c “按顺序”模式里默认插跳空格的逻辑是接近正解的)

具体实现还算好, Lexer/Parser 的区分、 Token 而非 Char 流的存在,核心原因是空格和注释对语法结构是无效的——最好能无视,免得解析器混杂
scannerless parser 很好,但跳空格其实有更容易的解决方法——为 Input stream 添加 filter ,到底还是 java 那一套自由组合的 stream 最好,连 skipped whitespaces 以及 AST element spans 它都可以往 Map<K,V> 存储好了,这就同时解决了 AST data class 不好写的问题,在不必使用这些信息时,也提升了性能,就从根源上解决了许多联带(代码复用、类型冗余和构造器隐式参数、分词解析器如何相互协调的)问题。

核心思想容易,实现上也有些问题—— Lexer 和 parser 在最近的语言里越来越模糊了,你可以看到 KotlinLexer 里会处理一些嵌套问题(就需要 push/pop state number 了),而且 >=fun():P<T>= 的区分也使得它必须识别一些本该由文法处理的模式——在过去这是不可想象的,C 的词法规则相当简单

这么做势必造成计算力的浪费(分词器和解析器对同一份数据做了类似的动作——检查它的嵌套结构),以及编程的冗余、重复代码,是应该努力避免的。

解析器与“分词器”之间的交流,显然是 parser combinator 的优势——它们的结构对程序员是完全透明的,可以自由定义、随意组合,让 Parser 去驱动其输入流上的 Lexer ,告诉分词器现在是什么状态,需不需要跳空格(例如 "" 里就不能跳);分词器是一个针对 Feed 流的状态机,本身也是一个 Feed ,而 onChar 的时候被动进行状态转移,就可以 filter 掉那些解析器不想看的字符,同时也能选择性地保留(如语法高亮) 的数据,一举多得。

有的观众就会问了:这么好的方法,比你高到不知哪里去的聪明人可多了,怎么就你想出来?
首先,不能说是没人想,要看编程实践怎么用、怎么组合这些技巧,不是说你去做了,效果就真的能像想象的那样好
其次,如果你没把代码重写 9遍,也容易被 Lexer/parser 和 scannerless 的那群既有实践误导,以为必须有 tokenizer ,或者流只能是一层,不能有“滤过”操作的
如果 LexerFeed被动性[2](非阻塞,要不然无法共享 string 等词法的定义)以及 Parser 对其的主动性(传递在解析词条类型号)不能被保证, 许多人对输入字符序列的抽象不够灵活(万恶之源),使得他们不能够发现这一点。 (所以你在编程的时候,记得重复的少写一点、稀奇的功能特性多写一点,说不定还能帮助你对程序模型整体的理解)
(这种设计也很好的发扬了 ParserKt 的 one-pass 设计,而 C 系语言 // /* 注释与除号的区分早有给 InfixPattern 扫描操作符的 TriePattern 专定子类可轻易完成,PKT 的组合性不加盖的)

但这个封装有很大问题—— ParserKt 最初只有 Feed { val peek; fun consume() } ,不像一些 nextChar()curChar() 数据视口不一致、命名迷惑的框架,它的流模型只允许程序员着眼一项(最本质的问题),结束时抛 Feed.End 异常
尽管这是根基(SliceFeed, Iterator/ReaderFeed 子类),它也是不切实际的,所以很快有了 Input(s: Feed): Feed, SourceLocated, ErrorHandler [1],以及一大堆 Feed 上试着 (this as Input) 的扩展函数,允许解析器带行号,尽量减小开销(统计行号信息是要在 Char 输入上,而一些输入根本无需 Input 的一些成员)
而那些接收 Input 的 Input ,就只能用一个代理(delegate)类 Input.By 去 proxy 这 underlying stream 实现的一些特性,这种问题严重后有点像“责任链”的字面含义——不断尝试 unwrap 一个 (可能是Input的)Feed ,寻找某个 trait 的实现者。

如果说你组织流嵌套的方法是手工的,应该不需要滥用多态去做“动态类型”,又或者是自动的——真的到那种“可组合”的地步吗?

最后我觉得,还是做 LexerInput(s:Input): Input.By 比较好,这样 LexerInput(Input(s=SliceFeed(Slice("wtf") ))) 这样的二层就会成为必要的组合法,如果需要其他层,则不能打破 Lexer 需求 Input (SourceLocated) 的类型, 还是取消这样的限制吧…… 真不知该怎样解决这问题 #parser #parsing #learn #Kotlin #project #suggest

[^1] 现在我更倾向 Input: Feed, FeedControl, SourceLocated { val states:Map<String,Any>; val onError; val isCompleteRead:Boolean }
isCompleteRead 是重新建模的(结果存逆波兰栈的)算符链解析器需要的,在非 complete read 时,可以像 Lua 一样直接进行简单的常量折叠,否则不仅不能折叠,还要存语法元素行号、前部空格等(重现原文所需的)信息
[^2] 其实我理解错了,这也是因为 LexerFeed 最开始是能自动识别底层输入的状态机,上级请求字符时肯定是要 blocking consume 直到非空格字符的,所谓非阻塞是因为对非空格单个字符它照样要处理状态转移;现在我倾向把它做成“能暂时屏蔽的自动 ws skip”一些,因为这才能真正统一复用文法/词法规则 ,虽然那样就没有花里胡哨的 List<Triple<Char,Int,Int>> 了(毕竟有效性在那)
duangsuse::Echo
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望 虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。 这里也有一个 initNewFrame + listen keyEvent & StringBuilder…
被冰封有理有据地怒斥了一顿…… 下次我还得委婉点,不对,得先对相应框架、库去学习一个 ,还得仔细对下稿子,不能搞错客观事实
冰封还说我对
Optimization for strings. That jimgui by default uses an inefficient way to convert java.lang.String into byte arrays that C++ is happy with. You can customize the string-to-bytes function yourself by using org.ice1000.jimgui.util.JImGuiUtil.setStringToBytes the default caching JImGuiUtil.cacheStringToBytes(), or use the more efficient alternative to java.lang.String -- org.ice1000.jimgui.JImStr, which is supposed to be created as global constants.
的理解是错误的,在此斧正注明一下

此外冰封最后说要把我 tg 也给 ban 了,可能是真的,也可能不是认真的 😰
duangsuse::Echo
被冰封有理有据地怒斥了一顿…… 下次我还得委婉点,不对,得先对相应框架、库去学习一个 ,还得仔细对下稿子,不能搞错客观事实 冰封还说我对 Optimization for strings. That jimgui by default uses an inefficient way to convert java.lang.String into byte arrays that C++ is happy with. You can customize the string-to-bytes function…
第二人格🌝:等你把新 ParserKt 搞出来,再写几个编译器、语言工具出来,对他们不就有底气了吗? 何必虚心提出交流,直接上去就是一堆 LiteratePy 降维细解博文实操代码,各种领域都加上,哪怕是不准确的,也能倒逼他们出来辟谣,有利于他人学习,岂不美哉?
#dev #plt #statement
>你不要再到处提我的名字了,并不能显得你很高大上
<“我觉得自己最大的特色就是并不想让任何人觉得自己高大上,但想让深奥的技术更亲民而已”
<如果说我能离开你们发展这么久(当然我并不会道德绑架自由人),却偏偏要靠着你们的名字骗小白的话,那才叫低劣呢 :x

但是,我会一直谨记这句话,不管现在能不能成功,但它是我的态度,就像三年前一样。我希望能一直这样。
一个人的名字多么狭隘,要做,就要做大的。
刚才我私信里说一定会研究下这个库(真是没事找事),只能先写下这个示例了
#Java #code
UI.render(Application().title("table").width(1200).height(500)) {
val colOpts = Column("Options").widgets(/*rendering widget instead of row-object property*/
Button(/*auto-id, must*/).text("OK").sameline(true).onClick { it.text((it.getData("rowData") as User).name) }
)
Window("w").fill().children(
Table("tbl").globalFilter(true).cellEditor(true).rowsPerPage(10).columns( //gfilter, cedit
*"name age country".split(' ').mapToArray { Column(it.capitalize()).field(it) }+arrayOf(colOpts)
))
}

TkGUI 目前无等价(Table 等 Model/View 建模到底如何做还存疑,已有 TreeWidget 可以做无 button cell 的),但有增添可能。
是很好了 (我猜是不是用了代码生成呢?),如果要提一点激进的建议,我觉得 Box/Size 这种模型可以尽早使用 Application(title = "a", size = 1200 xHeight 5000) ,此外可以 Lombok 省去构造器 new,当然如果真加 Kotlin 的话绝不能用 infix fun

不过我可以搞个超前示例,如果以后绝句写出来了,会是这样封装:

引记法 瓷 「配」
引全 瓷.元素配置
物 示例:窗体应用("table", 宽高(1200, 500)) 为
晚成的量 主表:表单
实现的事 布局() = 表单(
提取自 ("name age country"切分以' ')映为组再末追(选项列),〖名〗表单.列(名取大写“不是全大写”、项=名)。、
全局过滤=真、单元可编辑=真、每页行数=10
) 名为(主表) 配填满格
其中,量 选项列 = 表单.列("Options"、钮(内文="OK")配同行 点击时,内文=(上级数据作用户)的名字。 )

散的程度没有 ImGui 高,没有 UI.render( 和 Application,我觉得散是有好处的
感觉极其生草啊……
This media is not supported in your browser
VIEW IN TELEGRAM
吃饱了没事干,去研究这个像 builder 但却非常函数式的框架,因为它性能高而且定义式。
我们还是要…按照这个基本法,按照《中国民众健康暂行规定》…去规避…… 12点就睡大觉,没关系的
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
LINES=68,COLUMNS=236 mvn exec:java -Dexec.mainClass=JPlayer1 -Dexec.args=a.mp4 LINES=68,COLUMNS=236 mvn exec:java -Dexec.mainClass=JPlayer -Dexec.args='a_con.mp4 a.mp4.wav' 真棒, Yuuta 的一直可以运行,我的老出问题 🌝
mvn exec:java -Dexec.mainClass=JPlayer1 -Dexec.args=BadApple.mp4 54.07s user 8.04s system 119% cpu 51.925 total
mvn exec:java -Dexec.mainClass=JPlayer 42.69s user 7.59s system 120% cpu 41.633 total

Yuuta 又赢了。 好了,睡觉吧,争取下次能写出性能更好的版本来 😂
*注: Yuuta 原版是 BufferedWriter+StringBuilder 缓冲的,没有多余 flush ,但我们为了避免帧撕裂 flush 了许多次(有效果的),从某种意义讲我们还是可以更快的
新版支持 MECH(屏幕刷新方式),NCHUNK,SPEED 参数, NCHUNK=0 时禁用 queue rendering, -1 时多线程 queue, 默认环形缓冲区 queue
为测试我给原版支持了 SPEED 参数,设置得足够大使 Thread.sleep 不会运行。
This media is not supported in your browser
VIEW IN TELEGRAM
遇到了困难,写出了麻烦,代码出了瑕疵和误用缺检,或者说就是出了问题,就不做了,睡大觉!
This media is not supported in your browser
VIEW IN TELEGRAM
二倍速,第一个是 Yuuta 的,第二个是我的(bug 关系最后5s没有显示出 QAQ) ,最后一个是老大哥 C++ 的原速播放