mirror of
https://github.com/logos-storage/nim-leopard.git
synced 2026-01-02 13:43:08 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0478b12df9 | ||
|
|
2add2f1dc4 | ||
|
|
0817f39ccb | ||
|
|
a42d9a84a1 | ||
|
|
27941e9c59 | ||
|
|
b81147ad6a | ||
|
|
03f71498fc | ||
|
|
aa5f8d7748 | ||
|
|
7d74813fcf | ||
|
|
9ffc848ea2 | ||
|
|
6ccf760afa | ||
|
|
16cd331daa | ||
|
|
1d3b1b85d7 | ||
|
|
3e09d8113f | ||
|
|
895ff24ca6 | ||
|
|
ab5e030733 | ||
|
|
4d4fdf6210 | ||
|
|
1a6f2ab725 | ||
|
|
ae043fd262 | ||
|
|
0d1bdf4f00 | ||
|
|
ca63881613 | ||
|
|
0bc64c4829 | ||
|
|
2f0bcd72d1 | ||
|
|
159408b83f |
162
.github/workflows/test.yml
vendored
162
.github/workflows/test.yml
vendored
@ -1,161 +1,45 @@
|
||||
name: Tests
|
||||
|
||||
on: [pull_request, push]
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
env:
|
||||
NPROC: 2
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
cache_nonce: [ 1 ]
|
||||
nim_version: [ 1.2.18, 1.4.8, 1.6.6 ]
|
||||
platform:
|
||||
- {
|
||||
icon: 🐧,
|
||||
label: Linux,
|
||||
os: ubuntu,
|
||||
shell: bash --noprofile --norc -eo pipefail
|
||||
runner: ubuntu-latest
|
||||
}
|
||||
- {
|
||||
icon: 🍎,
|
||||
label: macOS,
|
||||
os: macos,
|
||||
shell: bash --noprofile --norc -eo pipefail
|
||||
runner: macos-latest
|
||||
}
|
||||
- {
|
||||
icon: 🏁,
|
||||
label: Windows,
|
||||
os: windows,
|
||||
shell: msys2
|
||||
runner: windows-latest
|
||||
}
|
||||
name: ${{ matrix.platform.icon }} ${{ matrix.platform.label }} - Nim v${{ matrix.nim_version }}
|
||||
runs-on: ${{ matrix.platform.os }}-latest
|
||||
# Earliest supported and latest nim
|
||||
nim: [1.6.18, "stable"]
|
||||
name: ${{ matrix.platform.icon }} ${{ matrix.platform.label }} - Nim v${{ matrix.nim }}
|
||||
runs-on: ${{ matrix.platform.runner }}
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.platform.shell }} {0}
|
||||
|
||||
shell: bash
|
||||
steps:
|
||||
# - name: Install tools and libraries via APT (Linux)
|
||||
# if: matrix.platform.os == 'ubuntu'
|
||||
# run: |
|
||||
# sudo apt update
|
||||
# sudo apt install -y \
|
||||
# ...
|
||||
|
||||
- name: Install tools and libraries via Homebrew (macOS)
|
||||
if: matrix.platform.os == 'macos'
|
||||
run: |
|
||||
brew update
|
||||
brew install \
|
||||
findutils \
|
||||
libomp
|
||||
|
||||
- name: Install tools and libraries via MSYS2 (Windows)
|
||||
if: matrix.platform.os == 'windows'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: UCRT64
|
||||
install: >
|
||||
base-devel
|
||||
git
|
||||
mingw-w64-ucrt-x86_64-cmake
|
||||
mingw-w64-ucrt-x86_64-toolchain
|
||||
|
||||
- name: Checkout sources from GitHub
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Calculate cache member paths
|
||||
id: calc-paths
|
||||
run: |
|
||||
if [[ ${{ matrix.platform.os }} = windows ]]; then
|
||||
echo "::set-output name=bash_env::$(cygpath -m "${HOME}")/.bash_env"
|
||||
echo "::set-output name=choosenim::$(cygpath -m "${USERPROFILE}")/.choosenim"
|
||||
echo "::set-output name=nimble::$(cygpath -m "${HOME}")/.nimble"
|
||||
else
|
||||
echo "::set-output name=bash_env::${HOME}/.bash_env"
|
||||
echo "::set-output name=choosenim::${HOME}/.choosenim"
|
||||
echo "::set-output name=nimble::${HOME}/.nimble"
|
||||
fi
|
||||
|
||||
- name: Restore choosenim and Nim tooling from cache
|
||||
id: choosenim-nim-tooling-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
${{ steps.calc-paths.outputs.bash_env }}
|
||||
${{ steps.calc-paths.outputs.choosenim }}
|
||||
${{ steps.calc-paths.outputs.nimble }}/bin
|
||||
key: ${{ matrix.platform.os }}-nim_version:${{ matrix.nim_version }}-cache_nonce:${{ matrix.cache_nonce }}
|
||||
|
||||
- name: Install choosenim and Nim tooling
|
||||
if: steps.choosenim-nim-tooling-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p "${HOME}/Downloads"
|
||||
cd "${HOME}/Downloads"
|
||||
curl https://nim-lang.org/choosenim/init.sh -sSf -O
|
||||
chmod +x init.sh
|
||||
if [[ ${{ matrix.platform.os }} = windows ]]; then
|
||||
mkdir -p "$(cygpath "${USERPROFILE}")/.nimble/bin"
|
||||
fi
|
||||
CHOOSENIM_CHOOSE_VERSION=${{ matrix.nim_version }} ./init.sh -y
|
||||
if [[ ${{ matrix.platform.os }} = windows ]]; then
|
||||
mv "$(cygpath "${USERPROFILE}")/.nimble" "${HOME}/"
|
||||
# intention is to rely only on libs provided by the OS and MSYS2 env
|
||||
rm -rf "${HOME}/.nimble/bin/"*.dll
|
||||
rm -rf "${HOME}/.nimble/bin/"*.pem
|
||||
fi
|
||||
echo 'export NIMBLE_DIR="${HOME}/.nimble"' >> "${HOME}/.bash_env"
|
||||
echo 'export PATH="${NIMBLE_DIR}/bin:${PATH}"' >> "${HOME}/.bash_env"
|
||||
|
||||
- name: Install project dependencies
|
||||
run: |
|
||||
source "${HOME}/.bash_env"
|
||||
cd "${NIMBLE_DIR}/bin"
|
||||
# delete broken symlinks, which can arise because e.g. the cache
|
||||
# restored a symlink that points to an executable within
|
||||
# ../pkgs/foo-1.2.3/ but the project's .nimble file has been updated
|
||||
# to install foo-#head; in the case of a broken symlink, nimble's
|
||||
# auto-overwrite fails
|
||||
if [[ ${{ matrix.platform.os }} = macos ]]; then
|
||||
gfind . -xtype l -delete
|
||||
else
|
||||
find . -xtype l -delete
|
||||
fi
|
||||
cd -
|
||||
nimble --accept install
|
||||
|
||||
- name: Build and run tests
|
||||
run: |
|
||||
source "${HOME}/.bash_env"
|
||||
if [[ ${{ matrix.platform.os }} = windows ]]; then
|
||||
touch tests/testleopard.exe
|
||||
else
|
||||
touch tests/testleopard
|
||||
fi
|
||||
if [[ ${{ matrix.platform.os }} = macos ]]; then
|
||||
export PATH="$(brew --prefix)/opt/llvm/bin:${PATH}"
|
||||
export LDFLAGS="-L$(brew --prefix)/opt/libomp/lib -L$(brew --prefix)/opt/llvm/lib -Wl,-rpath,$(brew --prefix)/opt/llvm/lib"
|
||||
compiler_extra_options="-d:LeopardCmakeFlags='-DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$(brew --prefix)/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix)/opt/llvm/bin/clang++' -d:LeopardExtraCompilerlags='-fopenmp' -d:LeopardExtraLinkerFlags='-fopenmp -L$(brew --prefix)/opt/libomp/lib'"
|
||||
fi
|
||||
if [[ ${{ matrix.nim_version }} = 1.2.* ]]; then
|
||||
eval nimble --verbose test -d:release --gc:refc ${compiler_extra_options}
|
||||
elif [[ ${{ matrix.nim_version }} = 1.4.* ]]; then
|
||||
eval nimble --verbose test -d:release --gc:refc ${compiler_extra_options}
|
||||
eval nimble --verbose test -d:release --gc:orc ${compiler_extra_options}
|
||||
else
|
||||
eval nimble --verbose test -d:release --mm:refc ${compiler_extra_options}
|
||||
eval nimble --verbose test -d:release --mm:orc ${compiler_extra_options}
|
||||
fi
|
||||
if [[ ${{ matrix.platform.os }} = macos ]]; then
|
||||
echo
|
||||
echo otool -L tests/testleopard
|
||||
otool -L tests/testleopard
|
||||
else
|
||||
echo
|
||||
echo ldd tests/testleopard
|
||||
ldd tests/testleopard
|
||||
fi
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: jiro4989/setup-nim-action@v2
|
||||
with:
|
||||
nim-version: ${{matrix.nim}}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install
|
||||
run: nimble install -y
|
||||
- name: Build and run tests
|
||||
run: |
|
||||
eval nimble --verbose test -d:release --mm:refc
|
||||
eval nimble --verbose test -d:release --mm:orc
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -11,3 +11,7 @@
|
||||
.vscode
|
||||
leopard.nims
|
||||
TODO
|
||||
|
||||
nimble.develop
|
||||
nimble.paths
|
||||
nimbledeps
|
||||
|
||||
@ -10,7 +10,7 @@ Nim wrapper for [Leopard-RS](https://github.com/catid/leopard): a fast library f
|
||||
## Requirements
|
||||
|
||||
* Same as Leopard-RS' requirements, e.g. CMake 3.7 or newer.
|
||||
* Nim 1.2 or newer.
|
||||
* Nim 1.6 or newer.
|
||||
|
||||
## Installation
|
||||
|
||||
@ -20,7 +20,7 @@ $ nimble install leopard
|
||||
```
|
||||
In a project's `.nimble` file
|
||||
```nim
|
||||
requires "leopard >= 0.0.2 & < 0.0.3"
|
||||
requires "leopard >= 0.1.0 & < 0.2.0"
|
||||
```
|
||||
In a [nimbus-build-system](https://github.com/status-im/nimbus-build-system) project
|
||||
```text
|
||||
@ -70,7 +70,7 @@ So, on macOS, when running `nimble test` of nim-leopard or compiling a project t
|
||||
```
|
||||
and these flags should be passed to `nim c`
|
||||
```text
|
||||
-d:LeopardCmakeFlags="-DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$(brew --prefix)/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix)/opt/llvm/bin/clang++" -d:LeopardExtraCompilerlags="-fopenmp" -d:LeopardExtraLinkerFlags="-fopenmp -L$(brew --prefix)/opt/libomp/lib"
|
||||
-d:LeopardCmakeFlags="-DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$(brew --prefix)/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix)/opt/llvm/bin/clang++" -d:LeopardExtraCompilerFlags="-fopenmp" -d:LeopardExtraLinkerFlags="-fopenmp -L$(brew --prefix)/opt/libomp/lib"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@ -1,2 +1,9 @@
|
||||
--styleCheck:usages
|
||||
--styleCheck:error
|
||||
--threads:on
|
||||
--tlsEmulation:off
|
||||
# begin Nimble config (version 2)
|
||||
--noNimblePath
|
||||
when withDir(thisDir(), system.fileExists("nimble.paths")):
|
||||
include "nimble.paths"
|
||||
# end Nimble config
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
mode = ScriptMode.Verbose
|
||||
|
||||
packageName = "leopard"
|
||||
version = "0.0.2"
|
||||
version = "0.1.1"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "A wrapper for Leopard-RS"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
installDirs = @["vendor"]
|
||||
|
||||
requires "nim >= 1.2.0",
|
||||
"stew",
|
||||
requires "nim >= 1.6.0",
|
||||
"unittest2",
|
||||
"upraises >= 0.1.0 & < 0.2.0"
|
||||
"results"
|
||||
|
||||
@ -7,12 +7,9 @@
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import pkg/upraises
|
||||
push: {.upraises: [].}
|
||||
{.push raises: [].}
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
import pkg/stew/results
|
||||
import pkg/results
|
||||
|
||||
import ./wrapper
|
||||
import ./utils
|
||||
@ -48,8 +45,8 @@ type
|
||||
|
||||
func encode*(
|
||||
self: var LeoEncoder,
|
||||
data,
|
||||
parity: var openArray[seq[byte]]): Result[void, cstring] =
|
||||
data,parity: ptr UncheckedArray[ptr UncheckedArray[byte]],
|
||||
dataLen,parityLen: int ): Result[void, cstring] =
|
||||
## Encode a list of buffers in `data` into a number of `bufSize` sized
|
||||
## `parity` buffers
|
||||
##
|
||||
@ -57,10 +54,10 @@ func encode*(
|
||||
## `parity` - list of parity `buffers` of size `bufSize`
|
||||
##
|
||||
|
||||
if data.len != self.buffers:
|
||||
if dataLen != self.buffers:
|
||||
return err("Number of data buffers should match!")
|
||||
|
||||
if parity.len != self.parity:
|
||||
if parityLen != self.parity:
|
||||
return err("Number of parity buffers should match!")
|
||||
|
||||
# zero encode work buffer to avoid corrupting with previous run
|
||||
@ -68,7 +65,7 @@ func encode*(
|
||||
zeroMem(self.workBufferPtr[i], self.bufSize)
|
||||
|
||||
# copy data into aligned buffer
|
||||
for i in 0..<data.len:
|
||||
for i in 0..<dataLen:
|
||||
copyMem(self.dataBufferPtr[i], addr data[i][0], self.bufSize)
|
||||
|
||||
let
|
||||
@ -77,14 +74,14 @@ func encode*(
|
||||
self.buffers.cuint,
|
||||
self.parity.cuint,
|
||||
self.workBufferCount.cuint,
|
||||
cast[ptr pointer](addr self.dataBufferPtr[0]),
|
||||
cast[LeoDataPtr](addr self.dataBufferPtr[0]),
|
||||
cast[ptr pointer](addr self.workBufferPtr[0]))
|
||||
|
||||
if ord(res) != ord(LeopardSuccess):
|
||||
return err(leoResultString(res.LeopardResult))
|
||||
|
||||
for i in 0..<parity.len:
|
||||
copyMem(addr parity[i][0], self.workBufferPtr[i], self.bufSize)
|
||||
for i in 0..<parityLen:
|
||||
copyMem(parity[i], self.workBufferPtr[i], self.bufSize)
|
||||
|
||||
return ok()
|
||||
|
||||
@ -92,7 +89,8 @@ func decode*(
|
||||
self: var LeoDecoder,
|
||||
data,
|
||||
parity,
|
||||
recovered: var openArray[seq[byte]]): Result[void, cstring] =
|
||||
recovered: ptr UncheckedArray[ptr UncheckedArray[byte]],
|
||||
dataLen,parityLen,recoveredLen: int): Result[void, cstring] =
|
||||
## Decode a list of buffers in `data` and `parity` into a list
|
||||
## of `recovered` buffers of `bufSize`. The list of `recovered`
|
||||
## buffers should be match the `Leo.buffers`
|
||||
@ -102,13 +100,13 @@ func decode*(
|
||||
## `recovered` - list of recovered `buffers` of size `bufSize`
|
||||
##
|
||||
|
||||
if data.len != self.buffers:
|
||||
if dataLen != self.buffers:
|
||||
return err("Number of data buffers should match!")
|
||||
|
||||
if parity.len != self.parity:
|
||||
if parityLen != self.parity:
|
||||
return err("Number of parity buffers should match!")
|
||||
|
||||
if recovered.len != self.buffers:
|
||||
if recoveredLen != self.buffers:
|
||||
return err("Number of recovered buffers should match buffers!")
|
||||
|
||||
# clean out work and data buffers
|
||||
@ -118,38 +116,38 @@ func decode*(
|
||||
for i in 0..<self.decodeBufferCount:
|
||||
zeroMem(self.decodeBufferPtr[i], self.bufSize)
|
||||
|
||||
for i in 0..<data.len:
|
||||
for i in 0..<dataLen:
|
||||
zeroMem(self.dataBufferPtr[i], self.bufSize)
|
||||
|
||||
# this is needed because erasures are nil pointers
|
||||
var
|
||||
dataPtr = newSeq[LeoBufferPtr](data.len)
|
||||
dataPtr = newSeq[LeoBufferPtr](dataLen)
|
||||
parityPtr = newSeq[LeoBufferPtr](self.workBufferCount)
|
||||
|
||||
# copy data into aligned buffer
|
||||
for i in 0..<data.len:
|
||||
if data[i].len > 0:
|
||||
copyMem(self.dataBufferPtr[i], addr data[i][0], self.bufSize)
|
||||
for i in 0..<dataLen:
|
||||
if not data[i].isNil:
|
||||
copyMem(self.dataBufferPtr[i],addr data[i][0], self.bufSize)
|
||||
dataPtr[i] = self.dataBufferPtr[i]
|
||||
else:
|
||||
dataPtr[i] = nil
|
||||
|
||||
# copy parity into aligned buffer
|
||||
for i in 0..<self.workBufferCount:
|
||||
if i < parity.len and parity[i].len > 0:
|
||||
if i < parityLen and not parity[i].isNil:
|
||||
copyMem(self.workBufferPtr[i], addr parity[i][0], self.bufSize)
|
||||
parityPtr[i] = self.workBufferPtr[i]
|
||||
else:
|
||||
parityPtr[i] = nil
|
||||
|
||||
let
|
||||
res = leo_decode(
|
||||
res = leoDecode(
|
||||
self.bufSize.culonglong,
|
||||
self.buffers.cuint,
|
||||
self.parity.cuint,
|
||||
self.decodeBufferCount.cuint,
|
||||
cast[ptr pointer](addr dataPtr[0]),
|
||||
cast[ptr pointer](addr parityPtr[0]),
|
||||
cast[LeoDataPtr](addr dataPtr[0]),
|
||||
cast[LeoDataPtr](addr parityPtr[0]),
|
||||
cast[ptr pointer](addr self.decodeBufferPtr[0]))
|
||||
|
||||
if ord(res) != ord(LeopardSuccess):
|
||||
@ -218,7 +216,7 @@ proc init[TT: Leo](
|
||||
# concurrently instantiate the library twice, and
|
||||
# might end up with two distinct versions - not a big
|
||||
# deal but will defeat the purpose of this `once` block
|
||||
if (let res = leoinit(); res.ord != LeopardSuccess.ord):
|
||||
if (let res = leoInit(); res.ord != LeopardSuccess.ord):
|
||||
return err(leoResultString(res.LeopardResult))
|
||||
|
||||
var
|
||||
|
||||
@ -7,10 +7,7 @@
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import pkg/upraises
|
||||
push: {.upraises: [].}
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
{.push raises: [].}
|
||||
|
||||
import system/ansi_c
|
||||
|
||||
|
||||
@ -7,10 +7,7 @@
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import pkg/upraises
|
||||
push: {.upraises: [].}
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
{.push raises: [].}
|
||||
|
||||
# From awr1: https://github.com/nim-lang/Nim/pull/11816/files
|
||||
|
||||
|
||||
@ -57,8 +57,7 @@
|
||||
## Conference on File and Storage Technologies, San Jose, 2013
|
||||
|
||||
|
||||
import pkg/upraises
|
||||
push: {.upraises: [].}
|
||||
{.push raises: [].}
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Build configuration
|
||||
@ -67,6 +66,9 @@ import std/compilesettings
|
||||
import std/os
|
||||
import std/strutils
|
||||
|
||||
type
|
||||
LeoDataPtr* {.importc: "const void* const*", bycopy.} = pointer
|
||||
|
||||
const
|
||||
LeopardCmakeFlags {.strdefine.} =
|
||||
when defined(macosx):
|
||||
@ -123,7 +125,7 @@ static:
|
||||
discard bash("mkdir -p", buildDirUnix)
|
||||
let cmd =
|
||||
@["cd", buildDirUnix, "&& cmake", leopardDirUnix, LeopardCmakeFlags,
|
||||
"&& make"]
|
||||
"&& make libleopard"]
|
||||
echo "\nBuilding Leopard-RS: " & cmd.join(" ")
|
||||
let (output, exitCode) = bashEx cmd
|
||||
echo output
|
||||
@ -136,7 +138,7 @@ static:
|
||||
discard gorge "mkdir -p " & buildDir
|
||||
let cmd =
|
||||
"cd " & buildDir & " && cmake " & LeopardDir & " " & LeopardCmakeFlags &
|
||||
" && make"
|
||||
" && make libleopard"
|
||||
echo "\nBuilding Leopard-RS: " & cmd
|
||||
let (output, exitCode) = gorgeEx cmd
|
||||
echo output
|
||||
@ -144,8 +146,8 @@ static:
|
||||
discard gorge "rm -rf " & buildDir
|
||||
raise (ref Defect)(msg: "Failed to build Leopard-RS")
|
||||
|
||||
{.passC: LeopardCompilerFlags & " " & LeopardExtraCompilerFlags.}
|
||||
{.passL: LeopardLinkerFlags & " " & LeopardExtraLinkerFlags.}
|
||||
{.passc: LeopardCompilerFlags & " " & LeopardExtraCompilerFlags.}
|
||||
{.passl: LeopardLinkerFlags & " " & LeopardExtraLinkerFlags.}
|
||||
|
||||
{.pragma: leo, cdecl, header: LeopardHeader.}
|
||||
|
||||
@ -225,7 +227,7 @@ proc leoEncode*(
|
||||
originalCount: cuint;
|
||||
recoveryCount: cuint;
|
||||
workCount: cuint;
|
||||
originalData: ptr pointer;
|
||||
originalData: LeoDataPtr;
|
||||
workData: ptr pointer): LeopardResult {.leo, importc: "leo_encode".}
|
||||
## Number of bytes in each data buffer
|
||||
## Number of original_data[] buffer pointers
|
||||
@ -240,7 +242,7 @@ proc leoEncode*(
|
||||
##
|
||||
## leo_decode_work_count()
|
||||
##
|
||||
## Calculate the number of work_data buffers to provide to leo_decode().
|
||||
## Calculate the number of work_data buffers to provide to leoDecode().
|
||||
##
|
||||
## The sum of original_count + recovery_count must not exceed 65536.
|
||||
##
|
||||
@ -251,7 +253,7 @@ proc leoEncode*(
|
||||
proc leoDecodeWorkCount*(originalCount: cuint; recoveryCount: cuint): cuint
|
||||
{.leo, importc: "leo_decode_work_count".}
|
||||
##
|
||||
## leo_decode()
|
||||
## leoDecode()
|
||||
##
|
||||
## Decode original data from recovery data.
|
||||
##
|
||||
@ -277,8 +279,8 @@ proc leoDecode*(
|
||||
originalCount: cuint;
|
||||
recoveryCount: cuint;
|
||||
workCount: cuint;
|
||||
originalData: ptr pointer;
|
||||
recoveryData: ptr pointer;
|
||||
originalData: LeoDataPtr;
|
||||
recoveryData: LeoDataPtr;
|
||||
workData: ptr pointer): LeopardResult {.leo, importc: "leo_decode".}
|
||||
## Number of bytes in each data buffer
|
||||
## Number of original_data[] buffer pointers
|
||||
|
||||
26
nimble.lock
Normal file
26
nimble.lock
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": 2,
|
||||
"packages": {
|
||||
"unittest2": {
|
||||
"version": "0.2.5",
|
||||
"vcsRevision": "26f2ef3ae0ec72a2a75bfe557e02e88f6a31c189",
|
||||
"url": "https://github.com/status-im/nim-unittest2",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "02bb3751ba9ddc3c17bfd89f2e41cb6bfb8fc0c9"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"version": "0.5.1",
|
||||
"vcsRevision": "df8113dda4c2d74d460a8fa98252b0b771bf1f27",
|
||||
"url": "https://github.com/arnetheduck/nim-results",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "a9c011f74bc9ed5c91103917b9f382b12e82a9e7"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tasks": {}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import std/random
|
||||
|
||||
import pkg/stew/results
|
||||
import pkg/results
|
||||
import ../leopard
|
||||
|
||||
proc randomCRCPacket*(data: var openArray[byte]) =
|
||||
@ -24,22 +24,22 @@ proc randomCRCPacket*(data: var openArray[byte]) =
|
||||
|
||||
copyMem(addr data[4], unsafeAddr crc, sizeof(crc))
|
||||
|
||||
proc checkCRCPacket*(data: openArray[byte]): bool =
|
||||
if data.len < 16:
|
||||
for d in data[1..data.high]:
|
||||
if d != data[0]:
|
||||
proc checkCRCPacket*(data: ptr UncheckedArray[byte], len: int): bool =
|
||||
if len < 16:
|
||||
for i in 1..<len:
|
||||
if data[i] != data[0]:
|
||||
raise (ref Defect)(msg: "Packet don't match")
|
||||
else:
|
||||
var
|
||||
crc = data.len.uint32
|
||||
crc = len.uint32
|
||||
packCrc: uint32
|
||||
packSize: uint32
|
||||
|
||||
copyMem(addr packSize, unsafeAddr data[0], sizeof(packSize))
|
||||
if packSize != data.len.uint:
|
||||
if packSize != len.uint:
|
||||
raise (ref Defect)(msg: "Packet size don't match!")
|
||||
|
||||
for i in 4..<data.len:
|
||||
for i in 4..<len:
|
||||
let v = data[i]
|
||||
crc = (crc shl 3) and (crc shr (32 - 3))
|
||||
crc += v
|
||||
@ -49,19 +49,43 @@ proc checkCRCPacket*(data: openArray[byte]): bool =
|
||||
if packCrc == crc:
|
||||
return true
|
||||
|
||||
proc dropRandomIdx*(bufs: var openArray[seq[byte]], dropCount: int) =
|
||||
proc dropRandomIdx*(bufs: ptr UncheckedArray[ptr UncheckedArray[byte]], bufsLen,dropCount: int) =
|
||||
var
|
||||
count = 0
|
||||
dups: seq[int]
|
||||
size = bufs.len
|
||||
size = bufsLen
|
||||
|
||||
while count < dropCount:
|
||||
let i = rand(0..<size)
|
||||
if dups.find(i) == -1:
|
||||
dups.add(i)
|
||||
bufs[i].setLen(0)
|
||||
bufs[i]=nil
|
||||
count.inc
|
||||
|
||||
proc createDoubleArray*(
|
||||
outerLen, innerLen: int
|
||||
): ptr UncheckedArray[ptr UncheckedArray[byte]] =
|
||||
# Allocate outer array
|
||||
result = cast[ptr UncheckedArray[ptr UncheckedArray[byte]]](alloc0(
|
||||
sizeof(ptr UncheckedArray[byte]) * outerLen
|
||||
))
|
||||
|
||||
# Allocate each inner array
|
||||
for i in 0 ..< outerLen:
|
||||
result[i] = cast[ptr UncheckedArray[byte]](alloc0(sizeof(byte) * innerLen))
|
||||
|
||||
proc freeDoubleArray*(
|
||||
arr: ptr UncheckedArray[ptr UncheckedArray[byte]], outerLen: int
|
||||
) =
|
||||
# Free each inner array
|
||||
for i in 0 ..< outerLen:
|
||||
if not arr[i].isNil:
|
||||
dealloc(arr[i])
|
||||
|
||||
# Free outer array
|
||||
if not arr.isNil:
|
||||
dealloc(arr)
|
||||
|
||||
proc testPackets*(
|
||||
buffers,
|
||||
parity,
|
||||
@ -72,35 +96,37 @@ proc testPackets*(
|
||||
decoder: var LeoDecoder): Result[void, cstring] =
|
||||
|
||||
var
|
||||
dataBuf = newSeqOfCap[seq[byte]](buffers)
|
||||
parityBuf = newSeqOfCap[seq[byte]](parity)
|
||||
recoveredBuf = newSeqOfCap[seq[byte]](buffers)
|
||||
dataBuf = createDoubleArray(buffers, bufSize)
|
||||
parityBuf = createDoubleArray(parity, bufSize)
|
||||
recoveredBuf = createDoubleArray(buffers, bufSize)
|
||||
|
||||
defer:
|
||||
freeDoubleArray(dataBuf, buffers)
|
||||
freeDoubleArray(parityBuf, parity)
|
||||
freeDoubleArray(recoveredBuf, buffers)
|
||||
|
||||
for _ in 0..<buffers:
|
||||
|
||||
|
||||
for i in 0..<buffers:
|
||||
var
|
||||
dataSeq = newSeq[byte](bufSize)
|
||||
|
||||
randomCRCPacket(dataSeq)
|
||||
dataBuf.add(dataSeq)
|
||||
copyMem(dataBuf[i],addr dataSeq[0],bufSize)
|
||||
|
||||
recoveredBuf.add(newSeq[byte](bufSize))
|
||||
|
||||
for _ in 0..<parity:
|
||||
parityBuf.add(newSeq[byte](bufSize))
|
||||
|
||||
encoder.encode(dataBuf, parityBuf).tryGet()
|
||||
encoder.encode(dataBuf, parityBuf,buffers,parity).tryGet()
|
||||
|
||||
if dataLosses > 0:
|
||||
dropRandomIdx(dataBuf, dataLosses)
|
||||
dropRandomIdx(dataBuf,buffers, dataLosses)
|
||||
|
||||
if parityLosses > 0:
|
||||
dropRandomIdx(parityBuf, parityLosses)
|
||||
dropRandomIdx(parityBuf,parity,parityLosses)
|
||||
|
||||
decoder.decode(dataBuf, parityBuf, recoveredBuf).tryGet()
|
||||
decoder.decode(dataBuf, parityBuf, recoveredBuf,buffers,parity,buffers).tryGet()
|
||||
|
||||
for i, d in dataBuf:
|
||||
if d.len <= 0:
|
||||
if not checkCRCPacket(recoveredBuf[i]):
|
||||
for i in 0..<buffers:
|
||||
if dataBuf[i].isNil:
|
||||
if not checkCRCPacket(recoveredBuf[i],bufSize):
|
||||
return err(("Check failed for packet " & $i).cstring)
|
||||
|
||||
ok()
|
||||
|
||||
@ -2,7 +2,7 @@ import std/random
|
||||
import std/sets
|
||||
|
||||
import pkg/unittest2
|
||||
import pkg/stew/results
|
||||
import pkg/results
|
||||
|
||||
import ../leopard
|
||||
import ./helpers
|
||||
@ -30,51 +30,74 @@ suite "Leopard Parametrization":
|
||||
|
||||
test "Should not allow encoding with invalid data buffer counts":
|
||||
var
|
||||
dataLen =3
|
||||
parityLen = 2
|
||||
leo = LeoEncoder.init(64, 4, 2).tryGet()
|
||||
data = newSeq[seq[byte]](3)
|
||||
parity = newSeq[seq[byte]](2)
|
||||
|
||||
data = createDoubleArray(dataLen, 64)
|
||||
parity = createDoubleArray(parityLen, 64)
|
||||
defer:
|
||||
freeDoubleArray(data, dataLen)
|
||||
freeDoubleArray(parity, parityLen)
|
||||
check:
|
||||
leo.encode(data, parity).error == "Number of data buffers should match!"
|
||||
leo.encode(data, parity,dataLen,parityLen).error == "Number of data buffers should match!"
|
||||
|
||||
test "Should not allow encoding with invalid parity buffer counts":
|
||||
var
|
||||
dataLen =4
|
||||
parityLen = 3
|
||||
leo = LeoEncoder.init(64, 4, 2).tryGet()
|
||||
data = newSeq[seq[byte]](4)
|
||||
parity = newSeq[seq[byte]](3)
|
||||
data = createDoubleArray(dataLen, 64)
|
||||
parity = createDoubleArray(parityLen, 64)
|
||||
|
||||
defer:
|
||||
freeDoubleArray(data, dataLen)
|
||||
freeDoubleArray(parity, parityLen)
|
||||
|
||||
check:
|
||||
leo.encode(data, parity).error == "Number of parity buffers should match!"
|
||||
leo.encode(data, parity,dataLen,parityLen).error == "Number of parity buffers should match!"
|
||||
|
||||
test "Should not allow decoding with invalid data buffer counts":
|
||||
var
|
||||
dataLen =3
|
||||
parityLen = 2
|
||||
leo = LeoDecoder.init(64, 4, 2).tryGet()
|
||||
data = newSeq[seq[byte]](3)
|
||||
parity = newSeq[seq[byte]](2)
|
||||
recovered = newSeq[seq[byte]](3)
|
||||
data = createDoubleArray(dataLen, 64)
|
||||
parity = createDoubleArray(parityLen, 64)
|
||||
recovered = createDoubleArray(dataLen, 64)
|
||||
|
||||
defer:
|
||||
freeDoubleArray(data, dataLen)
|
||||
freeDoubleArray(parity, parityLen)
|
||||
freeDoubleArray(recovered, dataLen)
|
||||
|
||||
check:
|
||||
leo.decode(data, parity, recovered).error == "Number of data buffers should match!"
|
||||
leo.decode(data, parity, recovered,dataLen,parityLen,dataLen).error == "Number of data buffers should match!"
|
||||
|
||||
test "Should not allow decoding with invalid data buffer counts":
|
||||
var
|
||||
dataLen =4
|
||||
parityLen = 1
|
||||
recoveredLen = 3
|
||||
leo = LeoDecoder.init(64, 4, 2).tryGet()
|
||||
data = newSeq[seq[byte]](4)
|
||||
parity = newSeq[seq[byte]](1)
|
||||
recovered = newSeq[seq[byte]](3)
|
||||
data = createDoubleArray(dataLen, 64)
|
||||
parity = createDoubleArray(parityLen, 64)
|
||||
recovered = createDoubleArray(recoveredLen, 64)
|
||||
|
||||
check:
|
||||
leo.decode(data, parity, recovered).error == "Number of parity buffers should match!"
|
||||
leo.decode(data, parity, recovered,dataLen,parityLen,recoveredLen).error == "Number of parity buffers should match!"
|
||||
|
||||
test "Should not allow decoding with invalid data buffer counts":
|
||||
var
|
||||
dataLen =4
|
||||
parityLen = 2
|
||||
recoveredLen = 3
|
||||
leo = LeoDecoder.init(64, 4, 2).tryGet()
|
||||
data = newSeq[seq[byte]](4)
|
||||
parity = newSeq[seq[byte]](2)
|
||||
recovered = newSeq[seq[byte]](3)
|
||||
data = createDoubleArray(dataLen, 64)
|
||||
parity = createDoubleArray(parityLen, 64)
|
||||
recovered = createDoubleArray(recoveredLen, 64)
|
||||
|
||||
check:
|
||||
leo.decode(data, parity, recovered).error == "Number of recovered buffers should match buffers!"
|
||||
leo.decode(data, parity, recovered,dataLen,parityLen,recoveredLen).error == "Number of recovered buffers should match buffers!"
|
||||
|
||||
suite "Leopard simple Encode/Decode":
|
||||
const
|
||||
@ -86,70 +109,76 @@ suite "Leopard simple Encode/Decode":
|
||||
var
|
||||
encoder: LeoEncoder
|
||||
decoder: LeoDecoder
|
||||
data: seq[seq[byte]]
|
||||
parity: seq[seq[byte]]
|
||||
recovered: seq[seq[byte]]
|
||||
data: ptr UncheckedArray[ptr UncheckedArray[byte]]
|
||||
parity: ptr UncheckedArray[ptr UncheckedArray[byte]]
|
||||
recovered: ptr UncheckedArray[ptr UncheckedArray[byte]]
|
||||
|
||||
setup:
|
||||
encoder = LeoEncoder.init(BufferSize, DataCount, ParityCount).tryGet()
|
||||
decoder = LeoDecoder.init(BufferSize, DataCount, ParityCount).tryGet()
|
||||
data = newSeq[seq[byte]](DataCount)
|
||||
parity = newSeq[seq[byte]](ParityCount)
|
||||
recovered = newSeq[seq[byte]](DataCount)
|
||||
data = createDoubleArray(DataCount, BufferSize)
|
||||
parity = createDoubleArray(ParityCount, BufferSize)
|
||||
recovered = createDoubleArray(DataCount, BufferSize)
|
||||
|
||||
teardown:
|
||||
freeDoubleArray(data, DataCount)
|
||||
freeDoubleArray(parity, ParityCount)
|
||||
freeDoubleArray(recovered, DataCount)
|
||||
encoder.free()
|
||||
decoder.free()
|
||||
|
||||
test "Test 2 data loses out of 4 possible":
|
||||
for i in 0..<DataCount:
|
||||
data[i] = newSeq[byte](BufferSize)
|
||||
recovered[i] = newSeq[byte](BufferSize)
|
||||
var
|
||||
str = TestString & " " & $i
|
||||
|
||||
copyMem(addr data[i][0], addr str[0], str.len)
|
||||
copyMem(data[i], addr str[0], str.len)
|
||||
|
||||
for i in 0..<ParityCount:
|
||||
parity[i] = newSeq[byte](BufferSize)
|
||||
|
||||
encoder.encode(data, parity).tryGet()
|
||||
encoder.encode(data, parity,DataCount,ParityCount).tryGet()
|
||||
|
||||
var
|
||||
data1 = data[0]
|
||||
data2 = data[1]
|
||||
data1 =cast[ptr UncheckedArray[byte]](allocShared0(sizeof(byte) * BufferSize))
|
||||
data2 = cast[ptr UncheckedArray[byte]](allocShared0(sizeof(byte) * BufferSize))
|
||||
|
||||
data[0].setLen(0)
|
||||
data[1].setLen(0)
|
||||
defer:
|
||||
deallocShared(data1)
|
||||
deallocShared(data2)
|
||||
|
||||
copyMem(data1,data[0], BufferSize)
|
||||
copyMem(data2,data[1], BufferSize)
|
||||
|
||||
data[0]=nil
|
||||
data[1]=nil
|
||||
|
||||
decoder.decode(data, parity, recovered).tryGet()
|
||||
decoder.decode(data, parity, recovered,DataCount,ParityCount,DataCount).tryGet()
|
||||
|
||||
check recovered[0] == data1
|
||||
check recovered[1] == data2
|
||||
check equalMem(recovered[0], data1, BufferSize)
|
||||
check equalMem(recovered[1], data2, BufferSize)
|
||||
|
||||
test "Test 1 data and 1 parity loss out of 4 possible":
|
||||
for i in 0..<DataCount:
|
||||
data[i] = newSeq[byte](BufferSize)
|
||||
recovered[i] = newSeq[byte](BufferSize)
|
||||
|
||||
var
|
||||
str = TestString & " " & $i
|
||||
|
||||
copyMem(addr data[i][0], addr str[0], str.len)
|
||||
|
||||
for i in 0..<ParityCount:
|
||||
parity[i] = newSeq[byte](BufferSize)
|
||||
encoder.encode(data, parity,DataCount,ParityCount).tryGet()
|
||||
|
||||
encoder.encode(data, parity).tryGet()
|
||||
|
||||
var data1 = cast[ptr UncheckedArray[byte]](allocShared0(sizeof(byte) * BufferSize))
|
||||
|
||||
var
|
||||
data1 = data[0]
|
||||
defer: deallocShared(data1)
|
||||
|
||||
data[0].setLen(0)
|
||||
parity[0].setLen(0)
|
||||
copyMem(data1,data[0], BufferSize)
|
||||
|
||||
data[0]=nil
|
||||
parity[0]=nil
|
||||
|
||||
decoder.decode(data, parity, recovered,DataCount,ParityCount,DataCount).tryGet()
|
||||
|
||||
check equalMem(recovered[0], data1, BufferSize)
|
||||
|
||||
decoder.decode(data, parity, recovered).tryGet()
|
||||
check recovered[0] == data1
|
||||
|
||||
suite "Leopard Encode/Decode":
|
||||
test "bufSize = 4096, K = 800, M = 200 - drop data = 200 data":
|
||||
|
||||
2
vendor/leopard
vendored
2
vendor/leopard
vendored
@ -1 +1 @@
|
||||
Subproject commit 20eb7c8bc5ba41349091addd4e374d4b74e9fb07
|
||||
Subproject commit 670c5e6ef8565e87cec005051fcd162b1b581add
|
||||
Loading…
x
Reference in New Issue
Block a user