Skip to content

Commit

Permalink
feat: impl for snowflake4cj
Browse files Browse the repository at this point in the history
  • Loading branch information
gtn1024 committed Sep 12, 2024
0 parents commit f431abb
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.vscode/
.cache/
*.macrocall
tmpFile*
*.gcno
*.gcda

target/
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div align="center">
<h1>snowflake4cj</h1>
<p>Snowflake algorithm for Cangjie</p>
</div>
<p align="center">
<img alt="" src="https://img.shields.io/badge/release-v1.0.0-brightgreen" style="display: inline-block;" />
<img alt="" src="https://img.shields.io/badge/cjc-v0.55.3-brightgreen" style="display: inline-block;" />
</p>

## 介绍 / Introduction

snowflake4cj 是一个基于 Cangjie 的雪花算法实现。

snowflake4cj is a snowflake algorithm implementation based on Cangjie.

## 安装 / Installation

```toml
# In the `dependencies` section of `cjpm.toml`
snowflake4cj = { git = "https://github.com/gtn1024/snowflake4cj.git", tag = "v1.0.0" }
```

## 使用 / Usage

```cj
import snowflake4cj.snowflake.Snowflake
main(): Int64 {
let snowflake = Snowflake(0, 0)
for (i in 0..1000) {
let id = snowflake.nextId()
println(id)
}
return 0
}
```
3 changes: 3 additions & 0 deletions cjpm.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
version = 0

[requires]
14 changes: 14 additions & 0 deletions cjpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[dependencies]

[package]
cjc-version = "0.55.3"
compile-option = ""
description = "Snowflake algorithm for Cangjie"
link-option = ""
name = "snowflake4cj"
output-type = "dynamic"
override-compile-option = ""
src-dir = ""
target-dir = ""
version = "1.0.0"
package-configuration = {}
1 change: 1 addition & 0 deletions src/snowflake.cj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package snowflake4cj
75 changes: 75 additions & 0 deletions src/snowflake/snowflake.cj
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package snowflake4cj.snowflake

import std.time.*
import std.sync.*

public class Snowflake {
internal let twepoch: Int64 = 1725148800000
internal let workerIdBits: Int64 = 5
internal let datacenterIdBits: Int64 = 5
internal let maxWorkerId: Int64 = -1 ^ (-1 << workerIdBits)
internal let maxDatacenterId: Int64 = -1 ^ (-1 << datacenterIdBits)
internal let sequenceBits: Int64 = 12
internal let workerIdShift: Int64 = sequenceBits
internal let datacenterIdShift: Int64 = sequenceBits + workerIdBits
internal let timestampLeftShift: Int64 = sequenceBits + workerIdBits + datacenterIdBits
internal let sequenceMask: Int64 = -1 ^ (-1 << sequenceBits)

internal let workerId: Int64
internal let datacenterId: Int64
internal var sequence: Int64 = 0
internal var lastTimestamp: Int64 = -1

public init(workerId: Int64, datacenterId: Int64) {
if (workerId > maxWorkerId || workerId < 0) {
throw IllegalArgumentException("workerId can't be greater than ${maxWorkerId} or less than 0")
}

if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw IllegalArgumentException("datacenterId can't be greater than ${maxWorkerId} or less than 0")
}

this.workerId = workerId
this.datacenterId = datacenterId
}

let mtx = ReentrantMutex()

public func nextId() {
synchronized (mtx) {
var timestamp = timeGen()

if (timestamp < lastTimestamp) {
throw IllegalStateException("Clock moved backwards. Refusing to generate id for ${lastTimestamp - timestamp} milliseconds")
}

if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask

if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp)
}
} else {
sequence = 0
}

lastTimestamp = timestamp

((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence
}
}

internal func tilNextMillis(lastTimestamp: Int64) {
var timestamp = timeGen()

while (timestamp <= lastTimestamp) {
timestamp = timeGen()
}

timestamp
}

internal func timeGen() {
DateTime.nowUTC().toUnixTimeStamp().toMilliseconds()
}
}
31 changes: 31 additions & 0 deletions src/snowflake/snowflake_test.cj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package snowflake4cj.snowflake

import std.unittest.*
import std.unittest.testmacro.*

@Test
func testSnowflake() {
let snowflake = Snowflake(0, 0)
var last = 0
for (i in 0..10000) {
let new = snowflake.nextId()
@Expect(new > last)
}
}

@Test
func testFailedWhenMachineIdIsInvalid() {
for (i in -1..50) {
for (j in -1..50) {
if (i < 0 || i > 31 || j < 0 || j > 31) {
@ExpectThrows[IllegalArgumentException]({
Snowflake(i, j)
})
} else {
let snowflake = Snowflake(i, j)
let id = snowflake.nextId()
@Expect(id > 0)
}
}
}
}

0 comments on commit f431abb

Please sign in to comment.