memo

とりあえずこれ使った
https://github.com/rust-lang/mdBook

センキュー
https://www.bioerrorlog.work/entry/mdbook-github-pages-cd

メモ書きに使っていこうかな…

git

前略、git使ってますか?初歩的なポイントとよく使うコマンドを覚えてしまいましょう。

はじめに

  • 初心者向けです
    • あまり使ったことがない
    • tortoise Git とかでやってる
    • commit pull push をよくわからないが使っている

みたいな人向けです。

基本的なところ

git はローカルリポジトリと、外部のリポジトリであるリモートリポジトリの二つに分けられる。 例えば、このドキュメントを管理しているローカルリポジトリは.gitだし、リモートリポジトリは下記で確認できる。

➜ git remote -v
origin  https://github.com/nichijo/nichijo.github.io.git (fetch)
origin  https://github.com/nichijo/nichijo.github.io.git (push)

gitは、ローカルリポジトリだけで動作できる。 svnはサーバ上で生きていく存在だが、gitはただ、任意のディレクトリでgit initとコマンドを打てばリポジトリが生成され、管理できる。

生まれたばかりのローカルリポジトリに、任意のファイルを管理させるには下記のようにする。

git add ./anyfiles.txt
git commit -m "commit message."

この時点でコミットログは下記の通りとなる。

gitGraph
    commit id: "HEAD" type: HIGHLIGHT

再度任意のファイルを変更/追加してコミットするとこうなる

gitGraph
    commit
    commit id: "HEAD" type: HIGHLIGHT

add + commit

add は、任意のファイルをコミット対象とするかどうかを決める。 例えば、前回のコミットから、ローカルファイルに以下のファイルの変更があったとする。

  • book.toml
  • src/SUMMARY.md
  • mermaid-init.js
  • mermaid.min.js
  • src/2023-04-07.md

どう変化しているかは git status コマンドで確認できる

➜ git status   
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   book.toml
        modified:   src/SUMMARY.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        mermaid-init.js
        mermaid.min.js
        src/2023-04-07.md

no changes added to commit (use "git add" and/or "git commit -a")

以下は、以前のコミットから変更があったようだ

  • book.toml
  • src/SUMMARY.md

こちらは、新規のファイルのようだ

  • mermaid-init.js
  • mermaid.min.js
  • src/2023-04-07.md

git add を使うと、この中から一部だけコミットすることができる

➜ git add .\book.toml .\mermaid-init.js .\mermaid.min.js 
➜ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   book.toml
        new file:   mermaid-init.js
        new file:   mermaid.min.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/SUMMARY.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/2023-04-07.md
➜ git commit -m "add mermaid support"
[main 2339875] add mermaid support
 3 files changed, 1289 insertions(+)
 create mode 100644 mermaid-init.js
 create mode 100644 mermaid.min.js

かくしてコミットログは下記のようになった

gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit id: "HEAD" type: HIGHLIGHT

branch

gitにはブランチという機能があり…あるコミットから、ソースコードの独立性を維持しながら複数の開発を進めることができる。 svnのブランチよりも気軽に扱えるため、gitを使う上では欠かせない機能といえる。

現在のコミットログはこう。現在位置はHEAD

gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit id: "HEAD" type: HIGHLIGHT

あなたは上司から、2件のアプリケーションの改修依頼を受けたとしよう。
一つめの改修では ViewAGodClass が。
二つ目の改修では ViewBGodClass の改修が必要だ!

classDiagram
    class GodClass
    class ViewA
    class ViewB

    GodClass <.. ViewA : use
    GodClass <.. ViewB : use

こういう場合、作業ごとにブランチを切ったほうが、作業が混沌としないで済む

git branch work1
git branch work2
gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit id: "HEAD"
    branch work1

作業1を進める。ある程度の作業ごとでコミットすると良いだろう

gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit
    branch work1
    commit id:"view1fix" type: HIGHLIGHT
    commit id:"godclass fix" type: HIGHLIGHT

ブランチの切り替えには checkout を使う。例えば下記は work1 で作業中の状態。

gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit
    branch work1
    commit
    commit id:"HEAD" type: HIGHLIGHT

チェックアウトをすると、ブランチのHEADへ移動する 移動すると、ファイルの状態もコミットの状態に戻る。

git checkout master
gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit id: "HEAD" type: HIGHLIGHT tag: "ココに移動"
    branch work1
    commit
    commit

合間合間に作業2を進めても良い

gitGraph
    commit id: "0-00a7a51"
    commit id: "1-0769b79"
    commit
    branch work1
    branch work2
    checkout work1
    commit
    checkout work2
    commit
    checkout work1
    commit
    checkout work2
    commit type: HIGHLIGHT tag:"ココで作業"

仮に途中で作業が不要になったりしたらば、ブランチを消せばよい

git branch -D work2

通常 git branch -d で消すが、mainブランチにマージしていないとエラーが出て怒られる。 なので git branch -D として強制的に削除する。

Java

だいたいコピペです

2023-03-24 java20

言語機能 / switch式のパターンマッチング強化 / 2nd preview

// 型によるマッチング
Object obj = 123L;
String formatted = switch (obj) {
    case Integer i -> String.format("int %d", i);
    case Long l    -> String.format("long %d", l);
    case Double d  -> String.format("double %f", d);
    case String s  -> String.format("String %s", s);
    default        -> obj.toString();
};

// ガード節
static void test(Object obj) {
    switch (obj) {
        case String s when s.length() == 1 -> ...
        case String s                      -> ...
        ...
    }
}

// null もできる
String s = null;
switch (s) {
   case "test" -> "テスト";
   case null -> "ぬるぽ";
   default -> "hello";
}

言語機能 / レコード パターン / 4th preview

static void printSum(Object obj) {
    if (obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}

record Point(int x, int y) {}

void printSum(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

API / Scoped Values (new! / Incubator)

// 同一スレッド内で値を共有したいとき
// これまでは ThreadLocal を使っていたが
// これは遅かったらしい
final ThreadLocal<String> STR = new ThreadLocal<>();

void start() {
  STR.set("test");
  proc1();
}

void proc1() {
  System.out.println(STR.get());
  proc2();
}

void proc2() {
  System.out.println(STR.get());
}

// これは早いらしい、よくわからないが
final ScopedValue<String> STR = new ScopedValue<>();

void start() {
    // where内でセットした値が run内部の STR 変数にセットされるような感じぽい
  ScopedValue.where(STR, "test")
    .run(() -> proc1());
}

void proc1() {
  System.out.println(STR.get());
  proc2();
}

void proc2() {
  System.out.println(STR.get());
}

API / Virtual Threads / 2nd Preview

// Java19から変化なし
// これまでのスレッドは java.lang.Thread で OSのスレッドを使っていた
// これは重く、呼び出しなどのボトルネックで作って捨てるような小さい処理ではあまり早くならなかった
// そのため、JDKによって提供されるスレッドの軽量実装を作ったのだった(Goのゴルーチンみたいなね)

// Thread.Builder
// Thread.ofVirtual()
// Thread.ofPlatform()
// が追加されたんだってよ
Thread t = Thread.ofPlatform().unstarted(() -> System.out.println("hello")); // VirtualThread[#000000]/new
t.start(); // hello

Thread t2 = Thread.ofVirtual().unstarted(() -> System.out.println("hello")); //VirtualThread[#000001]/new
t.start(); // hello
// 1件の処理時間が短く、数が多い処理は virtual threadが有利らしいっす

API / Structured Concurrency (2nd Incubator)

異なるスレッドで実行される複数のタスクを1つの作業単位として扱うことでエラーハンドリングやキャンセル処理などを簡素化でき、プログラムの信頼性や可観測性を強化できます。 らしい。複数のタスクをのうち、いずれかで例外が出たときに、一部だけでも成功していれば良しとする。とか、一部がNGだったら他も中断しちゃうとか。なんかそんな雰囲気を感じる。

Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Future<String>  user  = scope.fork(() -> findUser());
        Future<Integer> order = scope.fork(() -> fetchOrder());

        scope.join();           // Join both forks
        scope.throwIfFailed();  // ... and propagate errors

        // Here, both forks have succeeded, so compose their results
        return new Response(user.resultNow(), order.resultNow());
    }
}

API / Foreign Function & Memory API (2nd Preview)

わからん、ヒープ外のメモリを直接扱うAPIらしいっす。

// 1. Find foreign function on the C library path
Linker linker          = Linker.nativeLinker();
SymbolLookup stdlib    = linker.defaultLookup();
MethodHandle radixsort = linker.downcallHandle(stdlib.find("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings = { "mouse", "cat", "dog", "car" };
// 3. Use try-with-resources to manage the lifetime of off-heap memory
try (Arena offHeap = Arena.openConfined()) {
    // 4. Allocate a region of off-heap memory to store four pointers
    MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
    // 5. Copy the strings from on-heap to off-heap
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);
        pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);
    }
    // 6. Sort the off-heap data by calling the foreign function
    radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\0');
    // 7. Copy the (reordered) strings from off-heap to on-heap
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
        javaStrings[i] = cString.getUtf8String(0);
    }
} // 8. All off-heap memory is deallocated here
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

API / Vector API (6th Incubator)

わからんが、普通に数学的なベクタとかなんかそんな感じのやつじゃない?(適当)

import jdk.Incubator.vector.*;
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

void vectorComputation(float[] a, float[] b, float[] c) {

    for (int i = 0; i < a.length; i += SPECIES.length()) { // SPECIES.length() = 256bit / 32bit -> 8
        VectorMask<Float> m = SPECIES.indexInRange(i, a.length); // 端数がマスクされる
                                                                 // a.lengthが11でiが8のとき最初の3つしか要素がないので [TTT.....]
        // FloatVector va, vb, vc;
        FloatVector va = FloatVector.fromArray(SPECIES, a, i, m);
        FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m);
        FloatVector vc = va.mul(va).
                    add(vb.mul(vb)).
                    neg();
        vc.intoArray(c, i, m);
    }
}