Compare commits

..

18 Commits
0.1.0 ... main

Author SHA1 Message Date
Jacek Sieka
0478b12df9
Merge pull request #23 from logos-storage/no-upraises
chore: drop upraises
2025-12-11 09:44:36 +01:00
Jacek Sieka
2add2f1dc4
remove stew dep 2025-12-11 09:01:02 +01:00
Jacek Sieka
0817f39ccb
add nim stable testing 2025-12-11 08:55:22 +01:00
Jacek Sieka
a42d9a84a1
win 2025-12-11 08:52:57 +01:00
Jacek Sieka
27941e9c59
chore: drop upraises 2025-12-10 22:31:55 +01:00
Slava
b81147ad6a
Merge pull request #19 from codex-storage/feat/adjust-matrix
feat: run-on runner and remove os element from matrix
2025-02-12 11:12:50 +02:00
munna0908
03f71498fc
feat: enhance encode/decode procs for multithreading support (#20)
* update encode proc signature

* add new decode proc

* remove old encode/decode procs

* fix tests
2025-02-11 11:14:18 -08:00
Csaba Kiraly
aa5f8d7748
Merge pull request #16 from codex-storage/fix-readme
fix typo in command line example
2025-01-28 12:33:33 +01:00
Csaba Kiraly
7d74813fcf
fix typo in command line example
Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
2025-01-27 17:58:48 +01:00
Slava
9ffc848ea2
feat: run-on runner and remove os element from matrix 2025-01-27 18:57:31 +02:00
Csaba Kiraly
6ccf760afa
Merge pull request #18 from codex-storage/fix-ci-arm64
we need recursive checkout on arm64
2025-01-27 17:49:45 +01:00
Csaba Kiraly
16cd331daa
make it explicit that we want macos-14-arm64
even before, macos-14-arm64 was used by Github instead of
the specified macos-13 runner ...

Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
2025-01-17 20:02:13 +01:00
Csaba Kiraly
1d3b1b85d7
we need recursive checkout on arm64
Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
2025-01-17 19:57:44 +01:00
Ben Bierens
3e09d8113f
GCC-14 (#15)
* disables pointer-compatibility error in gcc-14

* Replaces no-error passC with importc pointer type definition

* simplifies CI

* fix attempt for leopard on mm:orc

* removes touch in ci

* removes showing of symbols

* attempt to fix macos if

* sets runners in ci

* sets shell to bash in ci

* removes cmake compiler flags from ci

* Removes conditional block for macos in ci
2024-08-28 09:30:34 +02:00
Giuliano Mega
895ff24ca6
Merge pull request #13 from codex-storage/chore/bump-upstream
bump upstream leopard
2024-06-26 10:04:27 -03:00
Eric
ab5e030733
bump upstream leopard
Attempt to prevent IndexDefect when no parity data
2024-06-20 13:33:57 +10:00
Eric
4d4fdf6210
Use nim v1.6+ (#12)
* Use nim v1.6+

nim-stew now requires nim >= 1.6, so nim-leopard must be bumped

* Use macos-13 (intel) runner image instead of arm
* change 1.2 to 1.6 in readme and .nimble
2024-06-20 13:20:55 +10:00
Ben Bierens
1a6f2ab725
enables stylecheck (#10)
* enables stylecheck

* attempt to fix mac build
2023-03-09 11:03:39 +01:00
13 changed files with 220 additions and 293 deletions

View File

@ -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 llvm@14)/bin:${PATH}"
export LDFLAGS="-L$(brew --prefix libomp)/lib -L$(brew --prefix llvm@14)/lib -Wl,-rpath,$(brew --prefix llvm@14)/lib"
compiler_extra_options="-d:LeopardCmakeFlags='-DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$(brew --prefix llvm@14)/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix llvm@14)/bin/clang++' -d:LeopardExtraCompilerlags='-fopenmp' -d:LeopardExtraLinkerFlags='-fopenmp -L$(brew --prefix 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

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ TODO
nimble.develop
nimble.paths
nimbledeps

View File

@ -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
@ -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

View File

@ -1,6 +1,9 @@
--styleCheck:usages
--styleCheck:error
--threads:on
--tlsEmulation:off
# begin Nimble config (version 1)
when fileExists("nimble.paths"):
# begin Nimble config (version 2)
--noNimblePath
when withDir(thisDir(), system.fileExists("nimble.paths")):
include "nimble.paths"
# end Nimble config

View File

@ -1,13 +1,12 @@
mode = ScriptMode.Verbose
packageName = "leopard"
version = "0.1.0"
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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):
@ -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

View File

@ -1,35 +1,26 @@
{
"version": 1,
"version": 2,
"packages": {
"unittest2": {
"version": "0.0.4",
"vcsRevision": "f180f596c88dfd266f746ed6f8dbebce39c824db",
"url": "https://github.com/status-im/nim-unittest2.git",
"version": "0.2.5",
"vcsRevision": "26f2ef3ae0ec72a2a75bfe557e02e88f6a31c189",
"url": "https://github.com/status-im/nim-unittest2",
"downloadMethod": "git",
"dependencies": [],
"checksums": {
"sha1": "fa309c41eaf6ef57895b9e603f2620a2f6e11780"
"sha1": "02bb3751ba9ddc3c17bfd89f2e41cb6bfb8fc0c9"
}
},
"upraises": {
"version": "0.1.0",
"vcsRevision": "ff4f8108e44fba9b35cac535ab63d3927e8fd3c2",
"url": "https://github.com/markspanbroek/upraises.git",
"results": {
"version": "0.5.1",
"vcsRevision": "df8113dda4c2d74d460a8fa98252b0b771bf1f27",
"url": "https://github.com/arnetheduck/nim-results",
"downloadMethod": "git",
"dependencies": [],
"checksums": {
"sha1": "a0243c8039e12d547dbb2e9c73789c16bb8bc956"
}
},
"stew": {
"version": "0.1.0",
"vcsRevision": "6ad35b876fb6ebe0dfee0f697af173acc47906ee",
"url": "https://github.com/status-im/nim-stew.git",
"downloadMethod": "git",
"dependencies": [],
"checksums": {
"sha1": "46d58c4feb457f3241e3347778334e325dce5268"
"sha1": "a9c011f74bc9ed5c91103917b9f382b12e82a9e7"
}
}
}
}
},
"tasks": {}
}

View File

@ -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()

View File

@ -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

@ -1 +1 @@
Subproject commit 20eb7c8bc5ba41349091addd4e374d4b74e9fb07
Subproject commit 670c5e6ef8565e87cec005051fcd162b1b581add