Verified Commit 05dd2260 authored by Artem Klevtsov's avatar Artem Klevtsov 😹

Swich to boost library

parent c5485023
Pipeline #120718413 passed with stages
in 10 minutes and 7 seconds
......@@ -9,16 +9,14 @@ Authors@R: c(
email = "a.a.klevtsov@gmail.com",
comment = c(ORCID = "0000-0003-0492-6647"))
)
Description: Provides funstion to generating a vector of Universally Unique Identifiers
(UUID) version 4. Library use the platform specific implementation or random device instead.
Description: Provides funstion to generating a vector of Universally Unique Identifiers (UUID).
Used the OpenMP library to improve performance.
URL: https://artemklevtsov.gitlab.io/rcppuuid, https://gitlab.com/artemklevtsov/rcppuuid
BugReports: https://gitlab.com/artemklevtsov/rcppuuid/issues
License: GPL (>= 2)
Imports: Rcpp (>= 1.0.3)
Suggests: tinytest (>= 1.1.0), uuid, microbenchmark
LinkingTo: Rcpp
Imports: Rcpp
Suggests: tinytest, uuid, microbenchmark
LinkingTo: Rcpp, BH
Encoding: UTF-8
NeedsCompilation: yes
SystemRequirements: C++11
RoxygenNote: 7.0.2
# Generated by roxygen2: do not edit by hand
export(uuid_generate)
export(uuid_generate_name)
export(uuid_generate_nil)
export(uuid_generate_random)
importFrom(Rcpp,sourceCpp)
useDynLib(RcppUUID, .registration = TRUE)
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#' @title
#' Generate a version 4 UUID
#'
#' @description
#' Function generates a set of Universally Unique Identifiers.
#'
#' @param n Number of generated UUIDs.
#'
#' @return Character vector with UUIDs.
#'
#' @rdname uuid_generate
#' @export
#'
#' @examples
#' uuid_generate(5)
#'
uuid_generate <- function(n = 1L) {
.Call(`_RcppUUID_uuid_generate`, n)
uuid_generate_random <- function(n = 1L) {
.Call(`_RcppUUID_uuid_generate_random`, n)
}
#' @rdname uuid_generate
#' @export
uuid_generate_nil <- function(n = 1L) {
.Call(`_RcppUUID_uuid_generate_nil`, n)
}
#' @rdname uuid_generate
#' @export
uuid_generate_name <- function(x) {
.Call(`_RcppUUID_uuid_generate_name`, x)
}
......@@ -2,7 +2,7 @@
#'
#' @description
#' Provides funstion to generating a vector of Universally Unique Identifiers
#' (UUID) version 4. Used the OpenMP library to improve performance.
#' (UUID). Used the OpenMP library to improve performance.
#'
#' @name RcppUUID
#' @docType package
......
#' @title
#' Generate UUID
#'
#' @description
#' Function generates a set of Universally Unique Identifiers.
#'
#' @param n Number of generated UUIDs.
#' @param x Character vector.
#'
#' @return Character vector with UUIDs.
#'
#' @name uuid_generate
#'
#'
#' @examples
#' # generate random UUIDs
#' uuid_generate_random(2)
#' # generate nil UUIDs
#' uuid_generate_nil(2)
#' # generate name UUIDs
#' uuid_generate_name(c("one", "two"))
#'
NULL
......@@ -10,6 +10,7 @@ knitr::opts_chunk$set(
comment = "#>",
fig.path = "README-"
)
options(width = 120)
```
# RcppUUID
......@@ -24,7 +25,7 @@ knitr::opts_chunk$set(
<!-- badges: end -->
R package to generate Universally Unique Identifiers (UUIDs) version 4. Library use the platform specific implementation or random device instead.
R package to generate Universally Unique Identifiers (UUIDs).
## Installation
......@@ -42,27 +43,25 @@ remotes::install_gitlab("artemklevtsov/rcppuuid")
This package contains the compiled code, therefore you have to use the [Rtools](https://cran.r-project.org/bin/windows/Rtools/) to install it on Windows.
To use random device instead platofrm specific implementation you can use the `--with-random-device` configure argument when install package from source.
## Usage
Generate single UUID:
```{r}
RcppUUID::uuid_generate(1)
RcppUUID::uuid_generate_random(1)
```
Generate multiple UUIDs:
```{r}
RcppUUID::uuid_generate(5)
RcppUUID::uuid_generate_random(5)
```
Check uniques:
```{r}
n <- 1000000
length(unique(RcppUUID::uuid_generate(n))) == n
length(unique(RcppUUID::uuid_generate_random(n))) == n
```
## Benchmarking
......@@ -72,7 +71,7 @@ Single UUID:
```{r}
microbenchmark::microbenchmark(
uuid = uuid::UUIDgenerate(FALSE),
RcppUUID = RcppUUID::uuid_generate(1)
RcppUUID = RcppUUID::uuid_generate_random(1)
)
```
......@@ -82,7 +81,7 @@ Multiple UUIDs:
n <- 10000
microbenchmark::microbenchmark(
uuid = replicate(n, uuid::UUIDgenerate(FALSE)),
RcppUUID = RcppUUID::uuid_generate(n)
RcppUUID = RcppUUID::uuid_generate_random(n)
)
```
......
......@@ -18,9 +18,7 @@ v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org
<!-- badges: end -->
R package to generate Universally Unique Identifiers (UUIDs) version 4.
Library use the platform specific implementation or random device
instead.
R package to generate Universally Unique Identifiers (UUIDs).
## Installation
......@@ -41,35 +39,28 @@ This package contains the compiled code, therefore you have to use the
[Rtools](https://cran.r-project.org/bin/windows/Rtools/) to install it
on Windows.
To use random device instead platofrm specific implementation you can
use the `--with-random-device` configure argument when install package
from source.
## Usage
Generate single UUID:
``` r
RcppUUID::uuid_generate(1)
#> [1] "79fab637-72d1-419d-b21b-b36bd393d107"
RcppUUID::uuid_generate_random(1)
#> [1] "94f99d02-9aef-4235-941f-733ba4c2e114"
```
Generate multiple UUIDs:
``` r
RcppUUID::uuid_generate(5)
#> [1] "3a2f9da7-a8f7-4b57-9219-96fdf9e7638e"
#> [2] "a222fbc7-739f-42f5-a1e2-3fc91f453fb9"
#> [3] "270058cd-0760-4862-ab2b-24340f32cc68"
#> [4] "1e51723c-5be7-4f8c-b7b9-a9a4b1c204b8"
#> [5] "6129660a-1f3f-4b36-b707-86243ef2f611"
RcppUUID::uuid_generate_random(5)
#> [1] "d7fcfd4a-6b3b-4c63-8086-815967264b7f" "145ca48d-013c-46f2-a0d4-23ef0b9a819a" "4a14d8de-c452-48ba-adc4-7495a389b061"
#> [4] "61176f2b-58e7-4b88-af48-7e3f00ab7ac3" "6d42e8b6-1e9b-4908-8689-bdd338050359"
```
Check uniques:
``` r
n <- 1000000
length(unique(RcppUUID::uuid_generate(n))) == n
length(unique(RcppUUID::uuid_generate_random(n))) == n
#> [1] TRUE
```
......@@ -80,12 +71,12 @@ Single UUID:
``` r
microbenchmark::microbenchmark(
uuid = uuid::UUIDgenerate(FALSE),
RcppUUID = RcppUUID::uuid_generate(1)
RcppUUID = RcppUUID::uuid_generate_random(1)
)
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> uuid 15.224 16.2105 36.42521 17.2045 17.7045 1960.891 100 a
#> RcppUUID 16.198 16.9845 21.05792 17.2740 17.6950 94.395 100 a
#> expr min lq mean median uq max neval cld
#> uuid 15.080 15.8810 36.09674 16.2625 16.635 1994.061 100 a
#> RcppUUID 8.394 9.1435 13.11459 9.8820 10.487 228.525 100 a
```
Multiple UUIDs:
......@@ -94,12 +85,12 @@ Multiple UUIDs:
n <- 10000
microbenchmark::microbenchmark(
uuid = replicate(n, uuid::UUIDgenerate(FALSE)),
RcppUUID = RcppUUID::uuid_generate(n)
RcppUUID = RcppUUID::uuid_generate_random(n)
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval cld
#> uuid 179.87545 201.20595 232.13646 222.35388 244.32753 467.21675 100 b
#> RcppUUID 50.82422 52.87099 54.39368 53.94923 55.16014 68.06015 100 a
#> expr min lq mean median uq max neval cld
#> uuid 174.885527 183.911932 203.315408 191.169173 214.918204 361.96847 100 b
#> RcppUUID 5.181347 5.462485 6.749716 5.752187 6.438479 36.75441 100 a
```
## Bug reports
......
#!/bin/sh
rm -f config.* src/Makevars src/snappy/snappy-stubs-public.h
rm -rf autom4te.cache
This diff is collapsed.
AC_PREREQ([2.69])
AC_INIT([RcppUUID],m4_esyscmd_s([awk '/^Version:/ {print $2}' DESCRIPTION]),[a.a.klevtsov@gmail.com])
AC_CONFIG_SRCDIR([src/RcppExports.cpp])
dnl find R home and set correct compiler + flags
if test -z "${R_HOME}" ; then
R_HOME=`R RHOME`
fi
AC_MSG_CHECKING([R_HOME])
if test -z "${R_HOME}"; then
AC_MSG_RESULT([No])
AC_MSG_ERROR([Can not find ${R_HOME}.])
fi
AC_MSG_RESULT([${R_HOME}])
R_BIN="${R_HOME}/bin/R"
dnl pick all flags for testing from R
CC=`"${R_BIN}" CMD config CC`
CXX=`"${R_BIN}" CMD config CXX`
CFLAGS=`"${R_BIN}" CMD config CFLAGS`
CPPFLAGS=`"${R_BIN}" CMD config CPPFLAGS`
LDFLAGS=`"${R_BIN}" CMD config LDFLAGS`
AC_PROG_CC(${CC})
AC_PROG_CXX(${CXX})
AC_REQUIRE_CPP
AC_LANG(C++)
dnl random-device compile flag
AC_ARG_WITH(
[random-device],
AS_HELP_STRING([--with-random-device],[Use C++ random device to generate UUID.]),
[USE_RANDOM_DEVICE=yes]
)
if test "x$USE_RANDOM_DEVICE" = "xyes"; then
AC_MSG_NOTICE([Use random device.])
PKG_CPPFLAGS=-DGUID_RANDOM
else
host_os=`uname -s`
case "${host_os}" in
Darwin*)
PKG_CPPFLAGS=-DGUID_CFUUID
PKG_LIBS=-Wl,-S
;;
Linux*)
AC_CHECK_HEADER([uuid/uuid.h],LIBUUID_HEADER=yes)
AC_CHECK_LIB([uuid],[uuid_generate],LIBUUID_LIB=yes)
if test "x${LIBUUID_HEADER}" = "xyes" && test "x${LIBUUID_LIB}" = "xyes"; then
PKG_CPPFLAGS=-DGUID_LIBUUID
PKG_LIBS="-Wl,-S -luuid"
else
PKG_CPPFLAGS=-DGUID_RANDOM
fi
;;
SunOS*)
AC_CHECK_HEADER([uuid/uuid.h],LIBUUID_HEADER=yes)
AC_CHECK_LIB([uuid],[uuid_generate],LIBUUID_LIB=yes)
if test "x${LIBUUID_HEADER}" = "xyes" && test "x${LIBUUID_LIB}" = "xyes"; then
PKG_CPPFLAGS=-DGUID_LIBUUID
PKG_LIBS=-luuid
else
PKG_CPPFLAGS=-DGUID_RANDOM
fi
;;
*)
PKG_CPPFLAGS=-DGUID_RANDOM
;;
esac
fi
AC_MSG_NOTICE([OS: ${host_os}])
AC_MSG_NOTICE([CC: ${CC}])
AC_MSG_NOTICE([CPP: ${CPP}])
AC_MSG_NOTICE([CXX: ${CXX}])
AC_MSG_NOTICE([PKG_CPPFLAGS: ${PKG_CPPFLAGS}])
AC_MSG_NOTICE([PKG_LIBS: ${PKG_LIBS}])
AC_MSG_NOTICE([${PACKAGE_NAME}: ${PACKAGE_VERSION}])
AC_SUBST([PKG_CPPFLAGS])
AC_SUBST([PKG_LIBS])
AC_CONFIG_FILES([src/Makevars])
AC_OUTPUT
#pragma once
#include <array>
#include <string>
#include <sstream>
#include <utility>
#include <iterator>
#include <iomanip>
#ifdef GUID_LIBUUID
#include <uuid/uuid.h>
#elif GUID_WINDOWS
#include <objbase.h>
#elif GUID_CFUUID
#include <CoreFoundation/CFUUID.h>
#elif GUID_RANDOM
#include <algorithm>
#include <functional>
#include <random>
#endif
namespace uuids {
/*
* UUID class
*/
class uuid {
public:
using value_t = unsigned char;
using data_t = std::array<value_t, 16>;
constexpr uuid() noexcept : data({}) {};
uuid(const data_t& arr) noexcept {
std::copy(std::begin(arr), std::end(arr), std::begin(data));
}
void swap(uuid& other) noexcept {
data.swap(other.data);
}
private:
data_t data{{ 0 }};
friend bool operator==(const uuid& lhs, const uuid& rhs) noexcept;
friend bool operator<(const uuid& lhs, const uuid& rhs) noexcept;
friend std::ostream &operator<<(std::ostream& s, const uuid& id);
};
bool operator==(const uuid& lhs, const uuid& rhs) noexcept {
return lhs.data == rhs.data;
}
bool operator!=(const uuid& lhs, const uuid& rhs) noexcept {
return !(lhs == rhs);
}
bool operator<(const uuid& lhs, const uuid& rhs) noexcept {
return lhs.data < rhs.data;
}
void swap(uuid& lhs, uuid& rhs) noexcept {
lhs.swap(rhs);
}
std::ostream &operator<<(std::ostream &s, const uuid& id) {
std::ios_base::fmtflags f(s.flags());
s << std::hex << std::setfill('0')
<< std::setw(2) << static_cast<int>(id.data[0])
<< std::setw(2) << static_cast<int>(id.data[1])
<< std::setw(2) << static_cast<int>(id.data[2])
<< std::setw(2) << static_cast<int>(id.data[3])
<< '-'
<< std::setw(2) << static_cast<int>(id.data[4])
<< std::setw(2) << static_cast<int>(id.data[5])
<< '-'
<< std::setw(2) << static_cast<int>(id.data[6])
<< std::setw(2) << static_cast<int>(id.data[7])
<< '-'
<< std::setw(2) << static_cast<int>(id.data[8])
<< std::setw(2) << static_cast<int>(id.data[9])
<< '-'
<< std::setw(2) << static_cast<int>(id.data[10])
<< std::setw(2) << static_cast<int>(id.data[11])
<< std::setw(2) << static_cast<int>(id.data[12])
<< std::setw(2) << static_cast<int>(id.data[13])
<< std::setw(2) << static_cast<int>(id.data[14])
<< std::setw(2) << static_cast<int>(id.data[15]);
s.flags(f);
return s;
}
std::string to_string(const uuid& id) {
std::stringstream ss;
ss << id;
return ss.str();
}
/*
* UUID generator class
*/
class uuid_generator {
public:
using value_t = unsigned char;
using data_t = std::array<value_t, 16>;
uuid operator()() {
#ifdef GUID_LIBUUID
uuid_t id;
uuid_generate(id);
data_t res = {
id[0],
id[1],
id[2],
id[3],
id[4],
id[5],
id[6],
id[7],
id[8],
id[9],
id[10],
id[11],
id[12],
id[13],
id[14],
id[15]
};
return uuid{std::move(res)};
#elif GUID_WINDOWS
GUID id;
CoCreateGuid(&id);
data_t res = {
static_cast<unsigned char>(((id.Data1 >> 24) & 0xFF)),
static_cast<unsigned char>(((id.Data1 >> 16) & 0xFF)),
static_cast<unsigned char>(((id.Data1 >> 8) & 0xFF)),
static_cast<unsigned char>(((id.Data1) & 0xff)),
static_cast<unsigned char>(((id.Data2 >> 8) & 0xFF)),
static_cast<unsigned char>(((id.Data2) & 0xff)),
static_cast<unsigned char>(((id.Data3 >> 8) & 0xFF)),
static_cast<unsigned char>(((id.Data3) & 0xFF)),
static_cast<unsigned char>(id.Data4[0]),
static_cast<unsigned char>(id.Data4[1]),
static_cast<unsigned char>(id.Data4[2]),
static_cast<unsigned char>(id.Data4[3]),
static_cast<unsigned char>(id.Data4[4]),
static_cast<unsigned char>(id.Data4[5]),
static_cast<unsigned char>(id.Data4[6]),
static_cast<unsigned char>(id.Data4[7])
};
return uuid{std::move(res)};
#elif GUID_CFUUID
auto id = CFUUIDCreate(NULL);
auto bytes = CFUUIDGetUUIDBytes(id);
CFRelease(id);
data_t res = {
bytes.byte0,
bytes.byte1,
bytes.byte2,
bytes.byte3,
bytes.byte4,
bytes.byte5,
bytes.byte6,
bytes.byte7,
bytes.byte8,
bytes.byte9,
bytes.byte10,
bytes.byte11,
bytes.byte12,
bytes.byte13,
bytes.byte14,
bytes.byte15
};
return uuid{std::move(res)};
#elif GUID_RANDOM
std::uniform_int_distribution<uint32_t> distribution;
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
uint8_t bytes[16];
for (int i = 0; i < 16; i += 4) {
*reinterpret_cast<uint32_t*>(bytes + i) = distribution(generator);
}
// variant must be 10xxxxxx
bytes[8] &= 0xBF;
bytes[8] |= 0x80;
// version must be 0100xxxx
bytes[6] &= 0x4F;
bytes[6] |= 0x40;
data_t res = {
bytes[0],
bytes[1],
bytes[2],
bytes[3],
bytes[4],
bytes[5],
bytes[6],
bytes[7],
bytes[8],
bytes[9],
bytes[10],
bytes[11],
bytes[12],
bytes[13],
bytes[14],
bytes[15]
};
return uuid{std::move(res)};
#endif
}
};
} // uuid
# regex pattern to validate
ptrn <- "[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}"
expect_error(uuid_generate(NULL))
# expect_error(uuid_generate(NA_integer_))
expect_error(uuid_generate(c(0, 0)))
expect_equal(uuid_generate(0), character(0))
expect_true(is.character(uuid_generate(1)))
expect_true(grepl(ptrn, uuid_generate(1)))
expect_equal(length(uuid_generate(1)), 1)
expect_equal(length(uuid_generate(5)), 5)
expect_equal(length(unique(uuid_generate(100))), 100)
# regex pattern to validate
ptrn <- "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
# test uuid_generate_random
expect_error(uuid_generate_random(NULL))
expect_error(uuid_generate_random(integer(0)))
# expect_error(uuid_generate_random(NA_integer_))
expect_error(uuid_generate_random(c(0, 0)))
expect_equal(uuid_generate_random(0), character(0))
expect_true(is.character(uuid_generate_random(1)))
expect_true(grepl(ptrn, uuid_generate_random(1)))
expect_equal(length(uuid_generate_random(1)), 1)
expect_equal(length(uuid_generate_random(5)), 5)
expect_equal(length(unique(uuid_generate_random(100))), 100)
# uuid_generate_nil
expect_error(uuid_generate_nil(NULL))
expect_error(uuid_generate_nil(integer(0)))
# expect_error(uuid_generate_nil(NA_integer_))
expect_error(uuid_generate_nil(c(0, 0)))
expect_equal(uuid_generate_nil(0), character(0))
expect_true(grepl(ptrn, uuid_generate_nil(1)))
expect_true(is.character(uuid_generate_nil(1)))
expect_equal(uuid_generate_nil(1), "00000000-0000-0000-0000-000000000000")
expect_equal(length(unique(uuid_generate_nil(100))), 1)