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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
我想死的心都有了,看来 @in @out 依然可以实现,不过要这样!作为一个 checker……
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
rangemap.zip
25.1 KB
第二版,更好更简单
duangsuse::Echo
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
哦,对了,不得不说一下 RangeMap 到底是怎么工作的
其实 RangeMap 本来应该是 template<> RangeMap<int, int>, 反正它的真名是 RayRangeMap,利用数学的『射线』进行建模优化的算法,也就利用 Comparable 泛化了一下……

val rm = RangeMap<Int, String>()
rm[0 until 1] = "0"
rm[1 until 4] = "123"
rm[4 until 6] = "45"

assert (0 in rm)
assert (3 in rm)
assert (rm.containsEdge(0))
assert (6 !in rm)
assert (rm[0] == "0")
assert (rm[3] == "123")
assert (rm[5] == "45")
assert (rm.containsShadow(5))

理论上,RangeMap 只需要 O(log2 n) 的复杂度即可查找到某一个项目,并且比 HashMap 节省空间。
RangeMap 是一个在有序的序列存储后端上执行二分查找的算法,所以可以达到这样的时间/空间复杂度
(其实本身不是特别复杂,不过作为一个类封装起来会好用很多)
rangemap.kra
649.4 KB
rangemap.png
113.6 KB
class Array
def lookupFirstGE(near, beg = 0, endInclusive = size-1)
puts("#{beg} until #{endInclusive}")
viewport = endInclusive - beg
if viewport == 0 then return self[beg] end
if viewport == 1 then return self[endInclusive] end
mid = (viewport+1) / 2; item = self[mid]
return case
when item == near then item
when item > near then lookupFirstGE(near, beg, mid-1)
when item < near then lookupFirstGE(near, mid+1, endInclusive)
end
end
end

写不出 算了
duangsuse::Echo
class Array def lookupFirstGE(near, beg = 0, endInclusive = size-1) puts("#{beg} until #{endInclusive}") viewport = endInclusive - beg if viewport == 0 then return self[beg] end if viewport == 1 then return self[endInclusive] end mid = (viewport+1)…
说实话,今天我都有点不想写 RangeMap 了,毕竟昨天因为害怕写不完的缘故,我凌晨两点才睡觉…… 彼时我喉咙还有点发炎,现在是非常发炎
(而且那一部分核心代码应该是必须得重写了,我没考虑到不能向下圆整的问题,我也不确定 (a+1)/b 是否就是向上圆整了)
duangsuse::Echo
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
我打算用循环写,毕竟循环更灵活,可以解决 floor div 导致的代码繁复问题,也不会陷入死循环(因为我不需要给 GT 的情况『留空』了,我只需记录最后 GT 的索引即可)
不写了、放弃了、累死了,这 Annotation Processor 是多麻烦,一个 AST 想解构还不容易啊…… 如果用 Visitor pattern 会方便很多,可我需要能够检查 path 的 Tree/Visitor,不知道有没有这种 API,这次只能暂时以二分查找最小的 (it >=k) 结尾吧,写点其他的吧…… #task
我还用 Resource Bundle,resources 简直就一大坑,我不该一上来就用 resources 的! #Java
或许我下次应该找一个大佬分享一下写 APT 的技巧,比如说,@NamePrefix("pref") class 怎么要求里面的 executable, filed, localvar 啊都拿这个做前缀…… 比如 @hasGetter @hasProtectedSetter @data 怎么实现……
我真的不想光写一个那啥,但是不用 Visitor 和对象内部状态解决那个树的访问问题实在太过分了,可有些东西我不知道该怎么办啊…… 一些东西容易混淆,比如 Class 的 type param list 和 TypeParameter…… 语法上是一样的
rangemap_1.zip
45.5 KB
duangsuse::Echo
不写了、放弃了、累死了,这 Annotation Processor 是多麻烦,一个 AST 想解构还不容易啊…… 如果用 Visitor pattern 会方便很多,可我需要能够检查 path 的 Tree/Visitor,不知道有没有这种 API,这次只能暂时以二分查找最小的 (it >=k) 结尾吧,写点其他的吧…… #task
#PL 通俗的方法是使用 package javax.annotation.processing.util;
ElementScanner8<R, P>#scan(Element e);

《深入理解 Java 虚拟机》那本书教的不对啊!javax.annotation.processing 不能拿来修改和生成语法树节点啊!!!空欢喜我一场!
package javax.annotation.processing;
public interface Filer {...}
呀,不错嘛,还提供有能够生成代码的东西(这样 GeekSpec 就可以直接利用 Java APT 集成了,也是个好想法)。

一个 javac 包含 locale, options, sourceVersion, messager, filer, types, elements 等多个好用的组件或信息

可见 annotation processor 还是很强大的,有意思的是,Annotation processor 连 IDE 的补全 API 都有 getCompletions(e, AnnotationMirror, ExecutableElement, userText): Iterable<out Completion>
居然花了两个小时!不过好歹是写完了 #Java
name_checker.zip
22.3 KB
This media is not supported in your browser
VIEW IN TELEGRAM
想要学习一下怎么写 #Java Annotation Processor 的同学们快来看辣,花了我两个小时……
也是个好康的,比 《深入理解 Java 虚拟机(第二版)》上的那个还简单,我没检查 A__SNAKE 这种双下划线的情况,全用的 regex,而且没有一个类超过一百行代码,绝对很省事
(虽然 APT 也未必是一个怎么样的技术,不过了解一下入门总还是好的,起码可以基于元数据编译期静态代码生成)

import org.intellij.lang.annotations.Language;

public enum CaseJudge {
snakeCase("(_?\\p{javaLowerCase})+"), ...;

@FunctionalInterface interface Checker { boolean isValid(String name); }
final Checker checker;
CaseJudge(@Language("regexp") String regex) { this(s -> s.matches(regex)); }
CaseJudge(Checker checker) { this.checker = checker; }
}

可能没有比这个版本写的更简单的了…… 原版是基于状态机和索引字符 codePointAt(int) + java.lang.Character,十分不好看
就是用一个 Visitor Pattern (ElementScanner8<Void/*res*/, Void/*arg0*/>) 先序遍历来检查语法树里的名字
duangsuse::Echo
居然花了两个小时!不过好歹是写完了 #Java
大家从 javac -cp out/production/name_checker/ -processor NameChecker src/BAD.java 里的这个 class NameChecker extends BaseNameChecker {
public synchronized void init(ProcessingEnvironment);
public boolean process(Set<out TypeElement> annotations, RoundEnvironment);
}
开始看就好了,process 就是检查一下,就上 ElementScanner#scan
duangsuse::Echo
大家从 javac -cp out/production/name_checker/ -processor NameChecker src/BAD.java 里的这个 class NameChecker extends BaseNameChecker { public synchronized void init(ProcessingEnvironment); public boolean process(Set<out TypeElement> annotations, RoundEnvironment);…
效果:
处理程序NameChecker与[]匹配并返回false。 (@SupportedAnnotationTypes("*")
src/BAD.java:4: 警告: `BAD' should be capitalized
public class BAD<tt> {
^
src/BAD.java:4: 警告: `tt' should be screamSnakeCased
public class BAD<tt> {
^
src/BAD.java:9: 警告: `NOT_A_CONSTANT' should be camelCased
    public static int NOT_A_CONSTANT = _FORTY_TWO;
^
src/BAD.java:11: 警告: `simpleArg' should be snakeCased
    protected void BADLY_NAMED(Object simpleArg) {
^
src/BAD.java:14: 警告: Method with the same name of class constructor is confusing
    public static  <tT> void BAD() {
^
src/BAD.java:14: 警告: `tT' should be screamSnakeCased
    public static  <tT> void BAD() {

当然,processor 也可以做更复杂的事情,比如检查类型(hides, overrides, subtype 什么的),除了不能改原有的代码……
👍1