Browse Source

update library; switch to tinytest; add vignette

master
boB Rudis 5 years ago
parent
commit
03470841f7
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 1
      .Rbuildignore
  2. 1
      .gitignore
  3. 3
      .travis.yml
  4. 61
      DESCRIPTION
  5. 9
      NEWS.md
  6. 11
      README.Rmd
  7. 84
      README.md
  8. 52
      appveyor.yml
  9. 27
      inst/tinytest/test_ulid.R
  10. 6
      src/ulid-main.cpp
  11. 5
      src/ulid.h
  12. 1005
      src/ulid_struct.h
  13. 617
      src/ulid_uint128.h
  14. 2
      tests/test-all.R
  15. 6
      tests/testthat/test-ulid.R
  16. 5
      tests/tinytest.R
  17. 2
      vignettes/.gitignore
  18. 45
      vignettes/intro-to-ulid.Rmd

1
.Rbuildignore

@ -12,3 +12,4 @@
^tmp$
^notes$
^\.gitlab-ci\.yml$
^appveyor\.yml$

1
.gitignore

@ -6,3 +6,4 @@
src/*.o
src/*.so
src/*.dll
inst/doc

3
.travis.yml

@ -1,6 +1,5 @@
language: R
sudo: false
cache: packages
after_success:
- Rscript -e 'covr::codecov()'
- Rscript -e 'covr::codecov()'

61
DESCRIPTION

@ -1,41 +1,42 @@
Package: ulid
Type: Package
Title: Generate Universally Unique Lexicographically Sortable Identifier
Version: 0.1.0
Date: 2018-12-28
Authors@R: c(
person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"),
comment = c(ORCID = "0000-0001-5670-2640")),
person("suyash", role = c("aut"),
comment = "ULID C++ Port <https://github.com/suyash/ulid/>")
)
Version: 0.3.0
Date: 2019-07-04
Authors@R: c( person("Bob", "Rudis", email = "bob@rud.is", role =
c("aut", "cre"), comment = c(ORCID = "0000-0001-5670-2640")),
person("suyash", role = c("aut"), comment = "ULID C++ Port
<https://github.com/suyash/ulid/>") )
Maintainer: Bob Rudis <bob@rud.is>
Description: Universally unique identifiers ('UUIDs') can be suboptimal for many
uses-cases because they aren't the most character efficient way of encoding
128 bits of randomness; v1/v2 versions are impractical in many environments,
as they require access to a unique, stable MAC address; v3/v5 versions require
a unique seed and produce randomly distributed IDs, which can cause fragmentation
in many data structures; v4 provides no other information than randomness which
can cause fragmentation in many data structures. 'ULIDs' (<https://github.com/ulid/spec>)
have 128-bit compatibility with 'UUID', 1.21e+24 unique ULIDs per millisecond,
are lexicographically sortable, canonically encoded as a 26 character string,
as opposed to the 36 character 'UUID', use Crockford's 'base32' for better
efficiency and readability (5 bits per character), are case insensitive,
have no special characters (i.e. are 'URL' safe) and have a onotonic sort order
(correctly detects and handles the same millisecond).
Description: Universally unique identifiers ('UUIDs') can be suboptimal
for many uses-cases because they aren't the most character
efficient way of encoding 128 bits of randomness; v1/v2 versions
are impractical in many environments, as they require access to a
unique, stable MAC address; v3/v5 versions require a unique seed
and produce randomly distributed IDs, which can cause
fragmentation in many data structures; v4 provides no other
information than randomness which can cause fragmentation in many
data structures. 'ULIDs' (<https://github.com/ulid/spec>) have
128-bit compatibility with 'UUID', 1.21e+24 unique ULIDs per
millisecond, are lexicographically sortable, canonically encoded
as a 26 character string, as opposed to the 36 character 'UUID',
use Crockford's 'base32' for better efficiency and readability (5
bits per character), are case insensitive, have no special
characters (i.e. are 'URL' safe) and have a onotonic sort order
(correctly detects and handles the same millisecond).
URL: https://gitlab.com/hrbrmstr/ulid
BugReports: https://gitlab.com/hrbrmstr/ulid/issues
SystemRequirements: C++11
NeedsCompilation: yes
Encoding: UTF-8
License: MIT + file LICENSE
Suggests:
testthat,
covr
Depends:
R (>= 3.2.0)
Imports:
Rcpp
Suggests:
covr,
tinytest,
knitr,
rmarkdown
Depends: R (>= 3.2.0)
Imports: Rcpp
RoxygenNote: 6.1.1
LinkingTo:
Rcpp
LinkingTo: Rcpp
VignetteBuilder: knitr

9
NEWS.md

@ -1,2 +1,11 @@
0.3.0
* Updated libary
* Uses R C random bits vs `std::rand()`
* Vignette
* Converted to {tinytest}
0.2.0
* Polished version
0.1.0
* Initial release

11
README.Rmd

@ -2,6 +2,11 @@
output: rmarkdown::github_document
---
[![Travis-CI Build Status](https://travis-ci.org/hrbrmstr/ulid.svg?branch=master)](https://travis-ci.org/hrbrmstr/ulid)
[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/hrbrmstr/ulid?branch=master&svg=true)](https://ci.appveyor.com/project/hrbrmstr/ulid)
[![Coverage Status](https://codecov.io/gh/hrbrmstr/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/ulid)
[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/ulid)](https://cran.r-project.org/package=ulid)
# ulid
Universally Unique Lexicographically Sortable Identifier
@ -65,8 +70,8 @@ The following functions are implemented:
## Installation
```{r eval=FALSE}
devtools::install_github("hrbrmstr/ulid")
```{r nstall-ex, results='asis', echo = FALSE}
hrbrpkghelpr::install_block()
```
```{r message=FALSE, warning=FALSE, error=FALSE, include=FALSE}
@ -113,4 +118,4 @@ unmarshal(ut)
```{r}
cloc::cloc_pkg_md()
```
```

84
README.md

@ -1,4 +1,12 @@
[![Travis-CI Build
Status](https://travis-ci.org/hrbrmstr/ulid.svg?branch=master)](https://travis-ci.org/hrbrmstr/ulid)
[![AppVeyor build
status](https://ci.appveyor.com/api/projects/status/github/hrbrmstr/ulid?branch=master&svg=true)](https://ci.appveyor.com/project/hrbrmstr/ulid)
[![Coverage
Status](https://codecov.io/gh/hrbrmstr/ulid/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/ulid)
[![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/ulid)](https://cran.r-project.org/package=ulid)
# ulid
Universally Unique Lexicographically Sortable Identifier
@ -73,6 +81,12 @@ The following functions are implemented:
## Installation
``` r
install.packages("ulid", repos = "https://cinc.rud.is")
# or
devtools::install_git("https://git.sr.ht/~hrbrmstr/ulid")
# or
devtools::install_gitlab("hrbrmstr/ulid")
# or
devtools::install_github("hrbrmstr/ulid")
```
@ -85,7 +99,7 @@ library(ulid)
packageVersion("ulid")
```
## [1] '0.1.0'
## [1] '0.3.0'
### One
@ -93,7 +107,7 @@ packageVersion("ulid")
ulid::ULIDgenerate()
```
## [1] "0001E2ERKHVPKZJ6FA6ZWHH1KS"
## [1] "0001EHX06QWTHZTAT6TE2GVAVT"
### Many
@ -101,11 +115,11 @@ ulid::ULIDgenerate()
(u <- ulid::ULIDgenerate(20))
```
## [1] "0001E2ERKHVX5QF5D59SX2E65T" "0001E2ERKHKD6MHKYB1G8JHN5X" "0001E2ERKHTK0XEHVV2G5877K9" "0001E2ERKHKFGG5NPN24PC1N0W"
## [5] "0001E2ERKH3F48CAKJCVMSCBKS" "0001E2ERKHF3N0B94VK05GTXCW" "0001E2ERKH24GCJ2CT3Z5WM1FD" "0001E2ERKH381RJ232KK7SMWQW"
## [9] "0001E2ERKH7NAZ1T4HR4ZRQRND" "0001E2ERKHSATC17G2QAPYXE0C" "0001E2ERKH76R83NFST3MZNW84" "0001E2ERKHFKS52SD8WJ8FHXMV"
## [13] "0001E2ERKHQM6VBM5JB235JJ1W" "0001E2ERKHXG2KNYWHHFS8X69Z" "0001E2ERKHQW821KPRM4GQFANJ" "0001E2ERKHD5KWTM5S345A3RP4"
## [17] "0001E2ERKH0D901W6KX66B1BHE" "0001E2ERKHKPHZBFSC16FC7FFC" "0001E2ERKHQQH7315GMY8HRYXV" "0001E2ERKH016YBAJAB7K9777T"
## [1] "0001EHX06Q1C0H9NQPZQW7YN65" "0001EHX06QN1D7PYNDZ33B7QF1" "0001EHX06QZHV13RGNDWAJ7VX9" "0001EHX06Q2XC40QWY7AFR8DCZ"
## [5] "0001EHX06QXWZRT9EJ1YM75214" "0001EHX06QYDSTG3KRWSKG01EE" "0001EHX06QNC8YWTX0H2M7HHYQ" "0001EHX06QFPBJWQ1PAQ1KXTJY"
## [9] "0001EHX06Q6HW1WE5GP8Q9J6D6" "0001EHX06Q3QEY4KF2DX0FKTFB" "0001EHX06QS3FDSPSHW2W7AB7X" "0001EHX06QS2VENPTAADWYKAQW"
## [13] "0001EHX06QQJ7XEK9ZDT5542SD" "0001EHX06QHWVRKRF2SC86KB3Z" "0001EHX06QKG0V1129FBA0A5XY" "0001EHX06QY66KTA09CB9KKQP8"
## [17] "0001EHX06QZ9VMBDT8YZMXK1B5" "0001EHX06QJ60ZFVA45DFAGB5R" "0001EHX06QC0CXK917QFWXA71M" "0001EHX06QBW2TTWPDAFG23J7E"
### Unmarshal
@ -114,26 +128,26 @@ unmarshal(u)
```
## ts rnd
## 1 2018-12-29 07:02:57 VX5QF5D59SX2E65T
## 2 2018-12-29 07:02:57 KD6MHKYB1G8JHN5X
## 3 2018-12-29 07:02:57 TK0XEHVV2G5877K9
## 4 2018-12-29 07:02:57 KFGG5NPN24PC1N0W
## 5 2018-12-29 07:02:57 3F48CAKJCVMSCBKS
## 6 2018-12-29 07:02:57 F3N0B94VK05GTXCW
## 7 2018-12-29 07:02:57 24GCJ2CT3Z5WM1FD
## 8 2018-12-29 07:02:57 381RJ232KK7SMWQW
## 9 2018-12-29 07:02:57 7NAZ1T4HR4ZRQRND
## 10 2018-12-29 07:02:57 SATC17G2QAPYXE0C
## 11 2018-12-29 07:02:57 76R83NFST3MZNW84
## 12 2018-12-29 07:02:57 FKS52SD8WJ8FHXMV
## 13 2018-12-29 07:02:57 QM6VBM5JB235JJ1W
## 14 2018-12-29 07:02:57 XG2KNYWHHFS8X69Z
## 15 2018-12-29 07:02:57 QW821KPRM4GQFANJ
## 16 2018-12-29 07:02:57 D5KWTM5S345A3RP4
## 17 2018-12-29 07:02:57 0D901W6KX66B1BHE
## 18 2018-12-29 07:02:57 KPHZBFSC16FC7FFC
## 19 2018-12-29 07:02:57 QQH7315GMY8HRYXV
## 20 2018-12-29 07:02:57 016YBAJAB7K9777T
## 1 2019-07-04 18:42:31 1C0H9NQPZQW7YN65
## 2 2019-07-04 18:42:31 N1D7PYNDZ33B7QF1
## 3 2019-07-04 18:42:31 ZHV13RGNDWAJ7VX9
## 4 2019-07-04 18:42:31 2XC40QWY7AFR8DCZ
## 5 2019-07-04 18:42:31 XWZRT9EJ1YM75214
## 6 2019-07-04 18:42:31 YDSTG3KRWSKG01EE
## 7 2019-07-04 18:42:31 NC8YWTX0H2M7HHYQ
## 8 2019-07-04 18:42:31 FPBJWQ1PAQ1KXTJY
## 9 2019-07-04 18:42:31 6HW1WE5GP8Q9J6D6
## 10 2019-07-04 18:42:31 3QEY4KF2DX0FKTFB
## 11 2019-07-04 18:42:31 S3FDSPSHW2W7AB7X
## 12 2019-07-04 18:42:31 S2VENPTAADWYKAQW
## 13 2019-07-04 18:42:31 QJ7XEK9ZDT5542SD
## 14 2019-07-04 18:42:31 HWVRKRF2SC86KB3Z
## 15 2019-07-04 18:42:31 KG0V1129FBA0A5XY
## 16 2019-07-04 18:42:31 Y66KTA09CB9KKQP8
## 17 2019-07-04 18:42:31 Z9VMBDT8YZMXK1B5
## 18 2019-07-04 18:42:31 J60ZFVA45DFAGB5R
## 19 2019-07-04 18:42:31 C0CXK917QFWXA71M
## 20 2019-07-04 18:42:31 BW2TTWPDAFG23J7E
### Use defined timestamps
@ -141,14 +155,14 @@ unmarshal(u)
(ut <- ts_generate(as.POSIXct("2017-11-01 15:00:00", origin="1970-01-01")))
```
## [1] "0001CZM6DGE66RJEY4N05F5R95"
## [1] "0001CZM6DGVRVF68B8AP8VATS0"
``` r
unmarshal(ut)
```
## ts rnd
## 1 2017-11-01 15:00:00 E66RJEY4N05F5R95
## 1 2017-11-01 15:00:00 VRVF68B8AP8VATS0
## Package Code Metrics
@ -156,9 +170,9 @@ unmarshal(ut)
cloc::cloc_pkg_md()
```
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :----------- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
| C/C++ Header | 3 | 0.27 | 755 | 0.87 | 231 | 0.78 | 264 | 0.57 |
| C++ | 2 | 0.18 | 81 | 0.09 | 22 | 0.07 | 37 | 0.08 |
| R | 5 | 0.45 | 17 | 0.02 | 7 | 0.02 | 95 | 0.20 |
| Rmd | 1 | 0.09 | 10 | 0.01 | 37 | 0.12 | 69 | 0.15 |
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :----------- | -------: | --: | --: | ---: | ----------: | ---: | -------: | ---: |
| C/C++ Header | 3 | 0.3 | 763 | 0.87 | 238 | 0.78 | 302 | 0.60 |
| C++ | 2 | 0.2 | 87 | 0.10 | 22 | 0.07 | 37 | 0.07 |
| R | 4 | 0.4 | 15 | 0.02 | 7 | 0.02 | 94 | 0.19 |
| Rmd | 1 | 0.1 | 10 | 0.01 | 38 | 0.12 | 73 | 0.14 |

52
appveyor.yml

@ -0,0 +1,52 @@
# DO NOT CHANGE the "init" and "install" sections below
# Download script file from GitHub
init:
ps: |
$ErrorActionPreference = "Stop"
Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1"
Import-Module '..\appveyor-tool.ps1'
install:
ps: Bootstrap
cache:
- C:\RLibrary
environment:
NOT_CRAN: true
# env vars that may need to be set, at least temporarily, from time to time
# see https://github.com/krlmlr/r-appveyor#readme for details
# USE_RTOOLS: true
# R_REMOTES_STANDALONE: true
# Adapt as necessary starting from here
build_script:
- travis-tool.sh install_deps
test_script:
- travis-tool.sh run_tests
on_failure:
- 7z a failure.zip *.Rcheck\*
- appveyor PushArtifact failure.zip
artifacts:
- path: '*.Rcheck\**\*.log'
name: Logs
- path: '*.Rcheck\**\*.out'
name: Logs
- path: '*.Rcheck\**\*.fail'
name: Logs
- path: '*.Rcheck\**\*.Rout'
name: Logs
- path: '\*_*.tar.gz'
name: Bits
- path: '\*_*.zip'
name: Bits

27
inst/tinytest/test_ulid.R

@ -0,0 +1,27 @@
library(ulid)
x <- ULIDgenerate()
expect_true(is.character(x))
expect_true(nchar(x) == 26)
x <- ULIDgenerate(20)
expect_true(is.character(x))
expect_true(length(x) == 20)
expect_true(sum(nchar(x)) == 520)
expect_true(all(rle(x)[["values"]] == x))
x <- unmarshal(x)
expect_true(is.data.frame(x))
expect_true(nrow(x) == 20)
expect_true(inherits(x[["ts"]], "POSIXct"))
expect_true(is.character(x[["rnd"]]))
expect_true(sum(nchar(x[["rnd"]])) == 320)
expect_true(all(rle(x[["rnd"]])[["values"]] == x[["rnd"]]))
x <- ts_generate(as.POSIXct("2017-11-01 15:00:00", origin="1970-01-01"))
y <- unmarshal(x)
expect_true(is.data.frame(y))
expect_true(y[["ts"]][[1]] == "2017-11-01 15:00:00")
expect_true(is.character(y[["rnd"]][[1]]))
expect_true(nchar(y[["rnd"]][[1]]) == 16)

6
src/ulid-main.cpp

@ -28,6 +28,12 @@ CharacterVector ts_generate(Rcpp::DatetimeVector tsv) {
return(c);
}
inline long intrand() {
GetRNGstate();
long ret = (long)(unif_rand()*RAND_MAX);
PutRNGstate();
return(ret);
}
//' Generate ULID
//'

5
src/ulid.h

@ -1,4 +1,5 @@
#pragma once
#ifndef ULID_HH
#define ULID_HH
// http://stackoverflow.com/a/23981011
#ifdef __SIZEOF_INT128__
@ -10,3 +11,5 @@
#else
#include "ulid_struct.h"
#endif // ULIDUINT128
#endif // ULID_HH

1005
src/ulid_struct.h

File diff suppressed because it is too large

617
src/ulid_uint128.h

@ -1,4 +1,5 @@
#pragma once
#ifndef ULID_UINT128_HH
#define ULID_UINT128_HH
#include <chrono>
#include <cstdlib>
@ -7,6 +8,8 @@
#include <random>
#include <vector>
extern long intrand();
namespace ulid {
/**
@ -18,87 +21,87 @@ typedef __uint128_t ULID;
* EncodeTime will encode the first 6 bytes of a uint8_t array to the passed
* timestamp
* */
void EncodeTime(time_t timestamp, ULID& ulid) {
ULID t = static_cast<uint8_t>(timestamp >> 40);
inline void EncodeTime(time_t timestamp, ULID& ulid) {
ULID t = static_cast<uint8_t>(timestamp >> 40);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 32);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 32);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 24);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 24);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 16);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 16);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 8);
t <<= 8;
t |= static_cast<uint8_t>(timestamp >> 8);
t <<= 8;
t |= static_cast<uint8_t>(timestamp);
t <<= 8;
t |= static_cast<uint8_t>(timestamp);
t <<= 80;
t <<= 80;
ULID mask = 1;
mask <<= 80;
mask--;
ULID mask = 1;
mask <<= 80;
mask--;
ulid = t | (ulid & mask);
ulid = t | (ulid & mask);
}
/**
* EncodeTimeNow will encode a ULID using the time obtained using std::time(nullptr)
* */
void EncodeTimeNow(ULID& ulid) {
EncodeTime(std::time(nullptr), ulid);
inline void EncodeTimeNow(ULID& ulid) {
EncodeTime(std::time(nullptr), ulid);
}
/**
* EncodeTimeSystemClockNow will encode a ULID using the time obtained using
* std::chrono::system_clock::now() by taking the timestamp in milliseconds.
* */
void EncodeTimeSystemClockNow(ULID& ulid) {
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
EncodeTime(ms.count(), ulid);
inline void EncodeTimeSystemClockNow(ULID& ulid) {
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
EncodeTime(ms.count(), ulid);
}
/**
* EncodeEntropy will encode the last 10 bytes of the passed uint8_t array with
* the values generated using the passed random number generator.
* */
void EncodeEntropy(const std::function<uint8_t()>& rng, ULID& ulid) {
ulid = (ulid >> 80) << 80;
inline void EncodeEntropy(const std::function<uint8_t()>& rng, ULID& ulid) {
ulid = (ulid >> 80) << 80;
ULID e = rng();
ULID e = rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
e <<= 8;
e |= rng();
ulid |= e;
ulid |= e;
}
/**
@ -109,118 +112,148 @@ void EncodeEntropy(const std::function<uint8_t()>& rng, ULID& ulid) {
void EncodeEntropyRand(ULID& ulid) {
ulid = (ulid >> 80) << 80;
ULID e = (std::rand() * 255ull) / RAND_MAX;
ULID e = (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
e <<= 8;
e |= (std::rand() * 255ull) / RAND_MAX;
e |= (intrand() * 255ull) / RAND_MAX;
// ULID e = (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
//
// e <<= 8;
// e |= (std::rand() * 255ull) / RAND_MAX;
ulid |= e;
}
std::uniform_int_distribution<uint8_t> Distribution_0_255(0, 255);
static std::uniform_int_distribution<uint8_t> Distribution_0_255(0, 255);
/**
* EncodeEntropyMt19937 will encode a ulid using std::mt19937
*
* It also creates a std::uniform_int_distribution to generate values in [0, 255]
* */
void EncodeEntropyMt19937(std::mt19937& generator, ULID& ulid) {
ulid = (ulid >> 80) << 80;
inline void EncodeEntropyMt19937(std::mt19937& generator, ULID& ulid) {
ulid = (ulid >> 80) << 80;
ULID e = Distribution_0_255(generator);
ULID e = Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
e <<= 8;
e |= Distribution_0_255(generator);
ulid |= e;
ulid |= e;
}
/**
* Encode will create an encoded ULID with a timestamp and a generator.
* */
void Encode(time_t timestamp, const std::function<uint8_t()>& rng, ULID& ulid) {
EncodeTime(timestamp, ulid);
EncodeEntropy(rng, ulid);
inline void Encode(time_t timestamp, const std::function<uint8_t()>& rng, ULID& ulid) {
EncodeTime(timestamp, ulid);
EncodeEntropy(rng, ulid);
}
/**
* EncodeNowRand = EncodeTimeNow + EncodeEntropyRand.
* */
void EncodeNowRand(ULID& ulid) {
EncodeTimeNow(ulid);
EncodeEntropyRand(ulid);
inline void EncodeNowRand(ULID& ulid) {
EncodeTimeNow(ulid);
EncodeEntropyRand(ulid);
}
/**
* Create will create a ULID with a timestamp and a generator.
* */
ULID Create(time_t timestamp, const std::function<uint8_t()>& rng) {
ULID ulid = 0;
Encode(timestamp, rng, ulid);
return ulid;
inline ULID Create(time_t timestamp, const std::function<uint8_t()>& rng) {
ULID ulid = 0;
Encode(timestamp, rng, ulid);
return ulid;
}
/**
* CreateNowRand:EncodeNowRand = Create:Encode.
* */
ULID CreateNowRand() {
ULID ulid = 0;
EncodeNowRand(ulid);
return ulid;
inline ULID CreateNowRand() {
ULID ulid = 0;
EncodeNowRand(ulid);
return ulid;
}
/**
* Crockford's Base32
* */
const char Encoding[33] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
static const char Encoding[33] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
/**
* MarshalTo will marshal a ULID to the passed character array.
@ -243,80 +276,80 @@ const char Encoding[33] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
* entropy:
* follows similarly, except now all components are set to 5 bits.
* */
void MarshalTo(const ULID& ulid, char dst[26]) {
// 10 byte timestamp
dst[0] = Encoding[(static_cast<uint8_t>(ulid >> 120) & 224) >> 5];
dst[1] = Encoding[static_cast<uint8_t>(ulid >> 120) & 31];
dst[2] = Encoding[(static_cast<uint8_t>(ulid >> 112) & 248) >> 3];
dst[3] = Encoding[((static_cast<uint8_t>(ulid >> 112) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 104) & 192) >> 6)];
dst[4] = Encoding[(static_cast<uint8_t>(ulid >> 104) & 62) >> 1];
dst[5] = Encoding[((static_cast<uint8_t>(ulid >> 104) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 96) & 240) >> 4)];
dst[6] = Encoding[((static_cast<uint8_t>(ulid >> 96) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 88) & 128) >> 7)];
dst[7] = Encoding[(static_cast<uint8_t>(ulid >> 88) & 124) >> 2];
dst[8] = Encoding[((static_cast<uint8_t>(ulid >> 88) & 3) << 3) | ((static_cast<uint8_t>(ulid >> 80) & 224) >> 5)];
dst[9] = Encoding[static_cast<uint8_t>(ulid >> 80) & 31];
// 16 bytes of entropy
dst[10] = Encoding[(static_cast<uint8_t>(ulid >> 72) & 248) >> 3];
dst[11] = Encoding[((static_cast<uint8_t>(ulid >> 72) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 64) & 192) >> 6)];
dst[12] = Encoding[(static_cast<uint8_t>(ulid >> 64) & 62) >> 1];
dst[13] = Encoding[((static_cast<uint8_t>(ulid >> 64) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 56) & 240) >> 4)];
dst[14] = Encoding[((static_cast<uint8_t>(ulid >> 56) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 48) & 128) >> 7)];
dst[15] = Encoding[(static_cast<uint8_t>(ulid >> 48) & 124) >> 2];
dst[16] = Encoding[((static_cast<uint8_t>(ulid >> 48) & 3) << 3) | ((static_cast<uint8_t>(ulid >> 40) & 224) >> 5)];
dst[17] = Encoding[static_cast<uint8_t>(ulid >> 40) & 31];
dst[18] = Encoding[(static_cast<uint8_t>(ulid >> 32) & 248) >> 3];
dst[19] = Encoding[((static_cast<uint8_t>(ulid >> 32) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 24) & 192) >> 6)];
dst[20] = Encoding[(static_cast<uint8_t>(ulid >> 24) & 62) >> 1];
dst[21] = Encoding[((static_cast<uint8_t>(ulid >> 24) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 16) & 240) >> 4)];
dst[22] = Encoding[((static_cast<uint8_t>(ulid >> 16) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 8) & 128) >> 7)];
dst[23] = Encoding[(static_cast<uint8_t>(ulid >> 8) & 124) >> 2];
dst[24] = Encoding[((static_cast<uint8_t>(ulid >> 8) & 3) << 3) | (((static_cast<uint8_t>(ulid)) & 224) >> 5)];
dst[25] = Encoding[(static_cast<uint8_t>(ulid)) & 31];
inline void MarshalTo(const ULID& ulid, char dst[26]) {
// 10 byte timestamp
dst[0] = Encoding[(static_cast<uint8_t>(ulid >> 120) & 224) >> 5];
dst[1] = Encoding[static_cast<uint8_t>(ulid >> 120) & 31];
dst[2] = Encoding[(static_cast<uint8_t>(ulid >> 112) & 248) >> 3];
dst[3] = Encoding[((static_cast<uint8_t>(ulid >> 112) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 104) & 192) >> 6)];
dst[4] = Encoding[(static_cast<uint8_t>(ulid >> 104) & 62) >> 1];
dst[5] = Encoding[((static_cast<uint8_t>(ulid >> 104) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 96) & 240) >> 4)];
dst[6] = Encoding[((static_cast<uint8_t>(ulid >> 96) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 88) & 128) >> 7)];
dst[7] = Encoding[(static_cast<uint8_t>(ulid >> 88) & 124) >> 2];
dst[8] = Encoding[((static_cast<uint8_t>(ulid >> 88) & 3) << 3) | ((static_cast<uint8_t>(ulid >> 80) & 224) >> 5)];
dst[9] = Encoding[static_cast<uint8_t>(ulid >> 80) & 31];
// 16 bytes of entropy
dst[10] = Encoding[(static_cast<uint8_t>(ulid >> 72) & 248) >> 3];
dst[11] = Encoding[((static_cast<uint8_t>(ulid >> 72) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 64) & 192) >> 6)];
dst[12] = Encoding[(static_cast<uint8_t>(ulid >> 64) & 62) >> 1];
dst[13] = Encoding[((static_cast<uint8_t>(ulid >> 64) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 56) & 240) >> 4)];
dst[14] = Encoding[((static_cast<uint8_t>(ulid >> 56) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 48) & 128) >> 7)];
dst[15] = Encoding[(static_cast<uint8_t>(ulid >> 48) & 124) >> 2];
dst[16] = Encoding[((static_cast<uint8_t>(ulid >> 48) & 3) << 3) | ((static_cast<uint8_t>(ulid >> 40) & 224) >> 5)];
dst[17] = Encoding[static_cast<uint8_t>(ulid >> 40) & 31];
dst[18] = Encoding[(static_cast<uint8_t>(ulid >> 32) & 248) >> 3];
dst[19] = Encoding[((static_cast<uint8_t>(ulid >> 32) & 7) << 2) | ((static_cast<uint8_t>(ulid >> 24) & 192) >> 6)];
dst[20] = Encoding[(static_cast<uint8_t>(ulid >> 24) & 62) >> 1];
dst[21] = Encoding[((static_cast<uint8_t>(ulid >> 24) & 1) << 4) | ((static_cast<uint8_t>(ulid >> 16) & 240) >> 4)];
dst[22] = Encoding[((static_cast<uint8_t>(ulid >> 16) & 15) << 1) | ((static_cast<uint8_t>(ulid >> 8) & 128) >> 7)];
dst[23] = Encoding[(static_cast<uint8_t>(ulid >> 8) & 124) >> 2];
dst[24] = Encoding[((static_cast<uint8_t>(ulid >> 8) & 3) << 3) | (((static_cast<uint8_t>(ulid)) & 224) >> 5)];
dst[25] = Encoding[(static_cast<uint8_t>(ulid)) & 31];
}
/**
* Marshal will marshal a ULID to a std::string.
* */
std::string Marshal(const ULID& ulid) {
char data[27];
data[26] = '\0';
MarshalTo(ulid, data);
return std::string(data);
inline std::string Marshal(const ULID& ulid) {
char data[27];
data[26] = '\0';
MarshalTo(ulid, data);
return std::string(data);
}
/**
* MarshalBinaryTo will Marshal a ULID to the passed byte array
* */
void MarshalBinaryTo(const ULID& ulid, uint8_t dst[16]) {
// timestamp
dst[0] = static_cast<uint8_t>(ulid >> 120);
dst[1] = static_cast<uint8_t>(ulid >> 112);
dst[2] = static_cast<uint8_t>(ulid >> 104);
dst[3] = static_cast<uint8_t>(ulid >> 96);
dst[4] = static_cast<uint8_t>(ulid >> 88);
dst[5] = static_cast<uint8_t>(ulid >> 80);
// entropy
dst[6] = static_cast<uint8_t>(ulid >> 72);
dst[7] = static_cast<uint8_t>(ulid >> 64);
dst[8] = static_cast<uint8_t>(ulid >> 56);
dst[9] = static_cast<uint8_t>(ulid >> 48);
dst[10] = static_cast<uint8_t>(ulid >> 40);
dst[11] = static_cast<uint8_t>(ulid >> 32);
dst[12] = static_cast<uint8_t>(ulid >> 24);
dst[13] = static_cast<uint8_t>(ulid >> 16);
dst[14] = static_cast<uint8_t>(ulid >> 8);
dst[15] = static_cast<uint8_t>(ulid);
inline void MarshalBinaryTo(const ULID& ulid, uint8_t dst[16]) {
// timestamp
dst[0] = static_cast<uint8_t>(ulid >> 120);
dst[1] = static_cast<uint8_t>(ulid >> 112);
dst[2] = static_cast<uint8_t>(ulid >> 104);
dst[3] = static_cast<uint8_t>(ulid >> 96);
dst[4] = static_cast<uint8_t>(ulid >> 88);
dst[5] = static_cast<uint8_t>(ulid >> 80);
// entropy
dst[6] = static_cast<uint8_t>(ulid >> 72);
dst[7] = static_cast<uint8_t>(ulid >> 64);
dst[8] = static_cast<uint8_t>(ulid >> 56);
dst[9] = static_cast<uint8_t>(ulid >> 48);
dst[10] = static_cast<uint8_t>(ulid >> 40);
dst[11] = static_cast<uint8_t>(ulid >> 32);
dst[12] = static_cast<uint8_t>(ulid >> 24);
dst[13] = static_cast<uint8_t>(ulid >> 16);
dst[14] = static_cast<uint8_t>(ulid >> 8);
dst[15] = static_cast<uint8_t>(ulid);
}
/**
* MarshalBinary will Marshal a ULID to a byte vector.
* */
std::vector<uint8_t> MarshalBinary(const ULID& ulid) {
std::vector<uint8_t> dst(16);
MarshalBinaryTo(ulid, dst.data());
return dst;
inline std::vector<uint8_t> MarshalBinary(const ULID& ulid) {
std::vector<uint8_t> dst(16);
MarshalBinaryTo(ulid, dst.data());
return dst;
}
/**
@ -325,178 +358,178 @@ std::vector<uint8_t> MarshalBinary(const ULID& ulid) {
* 48-57 are digits.
* 65-90 are capital alphabets.
* */
const uint8_t dec[256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* 0 1 2 3 4 5 6 7 */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
/* 8 9 */
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* 10(A) 11(B) 12(C) 13(D) 14(E) 15(F) 16(G) */
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
/*17(H) 18(J) 19(K) 20(M) 21(N) */
0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF,
/*22(P)23(Q)24(R) 25(S) 26(T) 27(V) 28(W) */
0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C,
/*29(X)30(Y)31(Z) */
0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
static const uint8_t dec[256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* 0 1 2 3 4 5 6 7 */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
/* 8 9 */
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* 10(A) 11(B) 12(C) 13(D) 14(E) 15(F) 16(G) */
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
/*17(H) 18(J) 19(K) 20(M) 21(N) */
0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF,
/*22(P)23(Q)24(R) 25(S) 26(T) 27(V) 28(W) */
0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C,
/*29(X)30(Y)31(Z) */
0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/**
* UnmarshalFrom will unmarshal a ULID from the passed character array.
* */
void UnmarshalFrom(const char str[26], ULID& ulid) {
// timestamp
ulid = (dec[int(str[0])] << 5) | dec[int(str[1])];
inline void UnmarshalFrom(const char str[26], ULID& ulid) {
// timestamp
ulid = (dec[int(str[0])] << 5) | dec[int(str[1])];
ulid <<= 8;
ulid |= (dec[int(str[2])] << 3) | (dec[int(str[3])] >> 2);
ulid <<= 8;
ulid |= (dec[int(str[2])] << 3) | (dec[int(str[3])] >> 2);
ulid <<= 8;
ulid |= (dec[int(str[3])] << 6) | (dec[int(str[4])] << 1) | (dec[int(str[5])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[3])] << 6) | (dec[int(str[4])] << 1) | (dec[int(str[5])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[5])] << 4) | (dec[int(str[6])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[5])] << 4) | (dec[int(str[6])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[6])] << 7) | (dec[int(str[7])] << 2) | (dec[int(str[8])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[6])] << 7) | (dec[int(str[7])] << 2) | (dec[int(str[8])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[8])] << 5) | dec[int(str[9])];
ulid <<= 8;
ulid |= (dec[int(str[8])] << 5) | dec[int(str[9])];
// entropy
ulid <<= 8;
ulid |= (dec[int(str[10])] << 3) | (dec[int(str[11])] >> 2);
// entropy
ulid <<= 8;
ulid |= (dec[int(str[10])] << 3) | (dec[int(str[11])] >> 2);
ulid <<= 8;
ulid |= (dec[int(str[11])] << 6) | (dec[int(str[12])] << 1) | (dec[int(str[13])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[11])] << 6) | (dec[int(str[12])] << 1) | (dec[int(str[13])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[13])] << 4) | (dec[int(str[14])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[13])] << 4) | (dec[int(str[14])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[14])] << 7) | (dec[int(str[15])] << 2) | (dec[int(str[16])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[14])] << 7) | (dec[int(str[15])] << 2) | (dec[int(str[16])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[16])] << 5) | dec[int(str[17])];
ulid <<= 8;
ulid |= (dec[int(str[16])] << 5) | dec[int(str[17])];
ulid <<= 8;
ulid |= (dec[int(str[18])] << 3) | (dec[int(str[19])] >> 2);
ulid <<= 8;
ulid |= (dec[int(str[18])] << 3) | (dec[int(str[19])] >> 2);
ulid <<= 8;
ulid |= (dec[int(str[19])] << 6) | (dec[int(str[20])] << 1) | (dec[int(str[21])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[19])] << 6) | (dec[int(str[20])] << 1) | (dec[int(str[21])] >> 4);
ulid <<= 8;
ulid |= (dec[int(str[21])] << 4) | (dec[int(str[22])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[21])] << 4) | (dec[int(str[22])] >> 1);
ulid <<= 8;
ulid |= (dec[int(str[22])] << 7) | (dec[int(str[23])] << 2) | (dec[int(str[24])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[22])] << 7) | (dec[int(str[23])] << 2) | (dec[int(str[24])] >> 3);
ulid <<= 8;
ulid |= (dec[int(str[24])] << 5) | dec[int(str[25])];
ulid <<= 8;
ulid |= (dec[int(str[24])] << 5) | dec[int(str[25])];
}
/**
* Unmarshal will create a new ULID by unmarshaling the passed string.
* */
ULID Unmarshal(const std::string& str) {
ULID ulid;
UnmarshalFrom(str.c_str(), ulid);
return ulid;
inline ULID Unmarshal(const std::string& str) {
ULID ulid;
UnmarshalFrom(str.c_str(), ulid);
return ulid;
}
/**
* UnmarshalBinaryFrom will unmarshal a ULID from the passed byte array.
* */
void UnmarshalBinaryFrom(const uint8_t b[16], ULID& ulid) {
// timestamp
ulid = b[0];
inline void UnmarshalBinaryFrom(const uint8_t b[16], ULID& ulid) {
// timestamp
ulid = b[0];
ulid <<= 8;
ulid |= b[1];
ulid <<= 8;
ulid |= b[1];
ulid <<= 8;
ulid |= b[2];
ulid <<= 8;
ulid |= b[2];
ulid <<= 8;
ulid |= b[3];
ulid <<= 8;
ulid |= b[3];
ulid <<= 8;
ulid |= b[4];
ulid <<= 8;
ulid |= b[4];
ulid <<= 8;
ulid |= b[5];
ulid <<= 8;
ulid |= b[5];
// entropy
ulid <<= 8;
ulid |= b[6];
// entropy
ulid <<= 8;
ulid |= b[6];
ulid <<= 8;
ulid |= b[7];
ulid <<= 8;
ulid |= b[7];
ulid <<= 8;
ulid |= b[8];
ulid <<= 8;
ulid |= b[8];
ulid <<= 8;
ulid |= b[9];
ulid <<= 8;
ulid |= b[9];
ulid <<= 8;
ulid |= b[10];
ulid <<= 8;
ulid |= b[10];
ulid <<= 8;
ulid |= b[11];
ulid <<= 8;
ulid |= b[11];
ulid <<= 8;
ulid |= b[12];
ulid <<= 8;
ulid |= b[12];
ulid <<= 8;
ulid |= b[13];
ulid <<= 8;
ulid |= b[13];
ulid <<= 8;
ulid |= b[14];
ulid <<= 8;
ulid |= b[14];
ulid <<= 8;
ulid |= b[15];
ulid <<= 8;
ulid |= b[15];
}
/**
* Unmarshal will create a new ULID by unmarshaling the passed byte vector.
* */
ULID UnmarshalBinary(const std::vector<uint8_t>& b) {
ULID ulid;
UnmarshalBinaryFrom(b.data(), ulid);
return ulid;
inline ULID UnmarshalBinary(const std::vector<uint8_t>& b) {
ULID ulid;
UnmarshalBinaryFrom(b.data(), ulid);
return ulid;
}
/**
@ -506,34 +539,36 @@ ULID UnmarshalBinary(const std::vector<uint8_t>& b) {
* 1 if ulid1 is Lexicographically after ulid2
* 0 if ulid1 is same as ulid2
* */
int CompareULIDs(const ULID& ulid1, const ULID& ulid2) {
return -2 * (ulid1 < ulid2) - 1 * (ulid1 == ulid2) + 1;
inline int CompareULIDs(const ULID& ulid1, const ULID& ulid2) {
return -2 * (ulid1 < ulid2) - 1 * (ulid1 == ulid2) + 1;
}
/**
* Time will extract the timestamp used to generate a ULID
* */
time_t Time(const ULID& ulid) {
time_t ans = 0;
inline time_t Time(const ULID& ulid) {
time_t ans = 0;
ans |= static_cast<uint8_t>(ulid >> 120);
ans |= static_cast<uint8_t>(ulid >> 120);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 112);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 112);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 104);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 104);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 96);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 96);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 88);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 88);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 80);
ans <<= 8;
ans |= static_cast<uint8_t>(ulid >> 80);
return ans;
return ans;
}
}; // namespace ulid
#endif // ULID_UINT128_HH

2
tests/test-all.R

@ -1,2 +0,0 @@
library(testthat)
test_check("ulid")

6
tests/testthat/test-ulid.R

@ -1,6 +0,0 @@
context("minimal package functionality")
test_that("we can do something", {
#expect_that(some_function(), is_a("data.frame"))
})

5
tests/tinytest.R

@ -0,0 +1,5 @@
if ( requireNamespace("tinytest", quietly=TRUE) ){
tinytest::test_package("ulid")
}

2
vignettes/.gitignore

@ -0,0 +1,2 @@
*.html
*.R

45
vignettes/intro-to-ulid.Rmd

@ -0,0 +1,45 @@
---
title: "Introduction to {ulid}"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Introduction to {ulid}}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
```{r setup}
library(ulid)
```
### One
```{r}
ulid::ULIDgenerate()
```
### Many
```{r}
(u <- ulid::ULIDgenerate(20))
```
### Unmarshal
```{r}
unmarshal(u)
```
### Use defined timestamps
```{r}
(ut <- ts_generate(as.POSIXct("2017-11-01 15:00:00", origin="1970-01-01")))
unmarshal(ut)
```
Loading…
Cancel
Save