Full Code of gecko0307/dlib for AI

master e99dda8575d2 cached
164 files
1.1 MB
298.0k tokens
1 requests
Download .txt
Showing preview only (1,165K chars total). Download the full file or copy to clipboard to get everything.
Repository: gecko0307/dlib
Branch: master
Commit: e99dda8575d2
Files: 164
Total size: 1.1 MB

Directory structure:
gitextract_13402xs3/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── test.yml
├── .gitignore
├── AUTHORS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── COPYING.md
├── Doxyfile
├── README.md
├── dlib/
│   ├── audio/
│   │   ├── io/
│   │   │   ├── package.d
│   │   │   └── wav.d
│   │   ├── package.d
│   │   ├── sample.d
│   │   ├── sound.d
│   │   ├── synth.d
│   │   └── unmanaged.d
│   ├── coding/
│   │   ├── package.d
│   │   ├── varint.d
│   │   └── zlib.d
│   ├── concurrency/
│   │   ├── package.d
│   │   ├── taskqueue.d
│   │   ├── threadpool.d
│   │   └── workerthread.d
│   ├── container/
│   │   ├── array.d
│   │   ├── bst.d
│   │   ├── buffer.d
│   │   ├── dict.d
│   │   ├── linkedlist.d
│   │   ├── mappedlist.d
│   │   ├── package.d
│   │   ├── queue.d
│   │   ├── spscqueue.d
│   │   └── stack.d
│   ├── core/
│   │   ├── bitio.d
│   │   ├── compound.d
│   │   ├── memory.d
│   │   ├── mutex.d
│   │   ├── oop.d
│   │   ├── ownership.d
│   │   ├── package.d
│   │   ├── stream.d
│   │   ├── thread.d
│   │   └── tuple.d
│   ├── filesystem/
│   │   ├── delegaterange.d
│   │   ├── dirrange.d
│   │   ├── filesystem.d
│   │   ├── local.d
│   │   ├── package.d
│   │   ├── posix/
│   │   │   ├── common.d
│   │   │   ├── directory.d
│   │   │   └── file.d
│   │   ├── stdfs.d
│   │   ├── stdposixdir.d
│   │   ├── stdwindowsdir.d
│   │   └── windows/
│   │       ├── common.d
│   │       ├── directory.d
│   │       └── file.d
│   ├── geometry/
│   │   ├── aabb.d
│   │   ├── frustum.d
│   │   ├── intersection.d
│   │   ├── mpr.d
│   │   ├── obb.d
│   │   ├── package.d
│   │   ├── plane.d
│   │   ├── ray.d
│   │   ├── sphere.d
│   │   ├── support.d
│   │   ├── triangle.d
│   │   ├── trimesh.d
│   │   └── utils.d
│   ├── image/
│   │   ├── animation.d
│   │   ├── arithmetics.d
│   │   ├── canvas.d
│   │   ├── color.d
│   │   ├── filters/
│   │   │   ├── binarization.d
│   │   │   ├── boxblur.d
│   │   │   ├── chromakey.d
│   │   │   ├── contrast.d
│   │   │   ├── convolution.d
│   │   │   ├── desaturate.d
│   │   │   ├── edgedetect.d
│   │   │   ├── histogram.d
│   │   │   ├── lens.d
│   │   │   ├── median.d
│   │   │   ├── morphology.d
│   │   │   ├── normalmap.d
│   │   │   ├── package.d
│   │   │   └── sharpen.d
│   │   ├── fthread.d
│   │   ├── hdri.d
│   │   ├── hsv.d
│   │   ├── image.d
│   │   ├── io/
│   │   │   ├── bmp.d
│   │   │   ├── hdr.d
│   │   │   ├── jpeg.d
│   │   │   ├── package.d
│   │   │   ├── png.d
│   │   │   ├── tga.d
│   │   │   └── utils.d
│   │   ├── package.d
│   │   ├── render/
│   │   │   ├── cosplasma.d
│   │   │   ├── package.d
│   │   │   ├── shapes.d
│   │   │   └── text.d
│   │   ├── resampling/
│   │   │   ├── bicubic.d
│   │   │   ├── bilinear.d
│   │   │   ├── lanczos.d
│   │   │   ├── nearest.d
│   │   │   └── package.d
│   │   ├── signal2d.d
│   │   ├── transform.d
│   │   └── unmanaged.d
│   ├── math/
│   │   ├── combinatorics.d
│   │   ├── complex.d
│   │   ├── decomposition.d
│   │   ├── diff.d
│   │   ├── dual.d
│   │   ├── dualquaternion.d
│   │   ├── fft.d
│   │   ├── hof.d
│   │   ├── interpolation/
│   │   │   ├── bezier.d
│   │   │   ├── catmullrom.d
│   │   │   ├── easing.d
│   │   │   ├── hermite.d
│   │   │   ├── linear.d
│   │   │   ├── nearest.d
│   │   │   ├── package.d
│   │   │   └── smoothstep.d
│   │   ├── linsolve.d
│   │   ├── matrix.d
│   │   ├── package.d
│   │   ├── quaternion.d
│   │   ├── sse.d
│   │   ├── tensor.d
│   │   ├── transformation.d
│   │   ├── utils.d
│   │   └── vector.d
│   ├── memory/
│   │   ├── allocator.d
│   │   ├── arena.d
│   │   ├── gcallocator.d
│   │   ├── mallocator.d
│   │   ├── mmappool.d
│   │   └── package.d
│   ├── network/
│   │   ├── errno.d
│   │   ├── package.d
│   │   ├── socket.d
│   │   └── url.d
│   ├── package.d
│   ├── random/
│   │   ├── package.d
│   │   └── random.d
│   ├── serialization/
│   │   ├── json.d
│   │   ├── package.d
│   │   └── xml.d
│   └── text/
│       ├── common.d
│       ├── encodings.d
│       ├── lexer.d
│       ├── package.d
│       ├── str.d
│       ├── utf16.d
│       ├── utf8.d
│       └── utils.d
└── dub.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*.{c,h,d,di,dd,sh}]
end_of_line = crlf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
charset = utf-8
dfmt_brace_style = allman
dfmt_soft_max_line_length = 120
dfmt_align_switch_statements = true
dfmt_outdent_attributes = true
dfmt_outdent_labels = true
dfmt_split_operator_at_line_end = true
dfmt_space_after_cast = false
dfmt_space_after_keywords = true
dfmt_space_before_function_parameters = false
dfmt_selective_import_space = false
dfmt_keep_line_breaks = true


================================================
FILE: .github/FUNDING.yml
================================================
patreon: gecko0307
liberapay: gecko0307


================================================
FILE: .github/workflows/test.yml
================================================
name: CI

on: 
  push:
    branches: [ master ]
    paths:
    - 'dlib/**'
    - 'dub.json'
    - '.github/workflows/**'
  pull_request:
    branches: [ master ]
    paths:
    - 'dlib/**'
    - 'dub.json'
    - '.github/workflows/**'

jobs:
  test:
    name: Dub Tests
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        dc: [dmd-latest, ldc-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v2
      - uses: dlang-community/setup-dlang@v1
        with:
          compiler: ${{ matrix.dc }}
      - name: Run tests
        run: dub test --build=unittest-cov
      - name: Run code coverage
        if: success()
        run: |
          curl https://codecov.io/bash > codecov.sh
          bash codecov.sh


================================================
FILE: .gitignore
================================================
# Compiled Object files
*.o
*.obj

# Compiled Static libraries
*.a
*.lib

# Executables
*.exe

# Dub files
.dub
dub.selections.json

# Dub test files
__test__library__
tests/

# Documentation
docs/
docs-doxygen/
docs.json
__dummy.html
documentation.chm

# Coverage files
*.lst

# Debug info
*.pdb

# Backup files
*~


================================================
FILE: AUTHORS.md
================================================
# dlib authors and contributors
* Core library - [Timur Gafarov aka gecko0307](https://github.com/gecko0307)
* Filesystem package, stream module - [Martin Cejp aka minexew](https://github.com/minexew)
* Memory package, socket module - [Eugene Wissner aka belka-ew](https://github.com/belka-ew)
* Image binarization, histogram generation, median filter - [LightHouse Software](http://lhs-blog.info/) / [Oleg Baharev aka aquaratixc](https://github.com/aquaratixc)
* TGA and BMP encoder, improved BMP decoder, bugfixes, unittests - [Roman Chistokhodov aka FreeSlave](https://github.com/FreeSlave)
* PNG decoder improvements - [Vadim Lopatin](https://github.com/buggins)
* Combinatorics module - Nick Papanastasiou
* Rectangle drawing - [Aaron Nédélec aka ReactiveAlkali](https://github.com/ReactiveAlkali)
* Vector swizzling assignment - [João Lourenço aka iK4tsu](https://github.com/iK4tsu)
* SSE vector math port for GDC - [Alexander Perfilyev](https://github.com/aperfilev)
* Bugfixes - [Andrey Penechko aka MrSmith33](https://github.com/MrSmith33), [Valeriy Fedotov](https://github.com/Valera), [Basile Burg aka SixthDot](https://github.com/SixthDot), [Ate Eskola aka dukc](https://github.com/dukc), [Martin Nowak aka dawg](https://github.com/MartinNowak), [Mathias Lang aka Geod24](https://github.com/Geod24), [Nick Treleaven aka ntrel](https://github.com/ntrel), [Nikolay Krasheninnikov aka GoodNike](https://github.com/GoodNike), [ijet](https://github.com/my-ijet), [TETYYS](https://github.com/TETYYS), [Razvan Nitu aka RazvanN7](https://github.com/RazvanN7), [Denis Feklushkin aka denizzzka](https://github.com/denizzzka)
* Additional unittests - [Roman Vlasov](https://github.com/VlasovRoman)


================================================
FILE: CHANGELOG.md
================================================
dlib 1.5.0 - TBD
----------------
- **dlib.math**
  - `trsMatrix` that creates a transformation matrix from translation/rotation/scaling a once, without three matrix multiplications
  - New easing function `easeOutElastic`.

dlib 1.4.1 - 1 Jan, 2026
------------------------
- **dlib.geometry**
  - Fix setting `OBB.center`.

dlib 1.4.0 - 1 Dec, 2025
------------------------
Changes since dlib 1.4.0 beta1:
- **dlib.math**
  - `Matrix.isAffine`, `Matrix.inverse`, `Matrix.getColumn`, `Quaternion.toMatrix4x4`, `Quaternion.toMatrix3x3` are now `const`.

dlib 1.4.0 beta1 - 31 Nov, 2025
-------------------------------
- **dlib.memory**
  - `dlib.memory.arena` - a general-purpose region-based memory allocator
- **dlib.container**
  - `dlib.container.spscqueue` - wait-free single-producer single-consumer queue
  - `dlib.container.mappedlist` - a list with string-mapped indices
- **dlib.math**
  - New function `wrapAngle` in `dlib.math.utils`.

dlib 1.3.3 - 30 Aug, 2025
-------------------------
- **dlib.serialization**
  - Fix bugs in `dlib.serialization.json`.

dlib 1.3.2 - 1 May, 2025
------------------------
- **dlib.math**
  - `lookAtMatrix` now checks for matching eye and up directions
  - Fix unittest for vector swizzling.

dlib 1.3.1 - 10 Mar, 2025
-------------------------
- **dlib.math**
  -  Limit `dlib.math.sse` for x86_64 only
  - `dlib.math.complex.zeta` was removed due to its broken status.

dlib 1.3.0 - 21 Feb, 2023
-------------------------
No changes since dlib 1.3.0 beta1.

dlib 1.3.0 beta1 - 14 Feb, 2023
-------------------------------
- **dlib.random**
  - New module `dlib.random.random` that implements `random`, a pseudo-random number generator based on C `rand`
- **dlib.math**
  - Function that computes quadratic Bézier curve - `dlib.math.interpolation.bezierQuadratic`
  - GNU D Compiler (GDC) support in `dlib.math.sse`

dlib 1.2.1 - 30 Aug, 2023
-------------------------
- **dlib.image**
  - Median filter (`dlib.image.filters.median`)
- **dlib.filesystem**
  - Bugfixes in `dlib.filesystem.posix.common`
- **dlib.core**
  - `dlib.core.thread`: fix deprecations in Windows multithreading API signatures
- **dlib.math**
  - Fix unittest for `dlib.math.utils.nextPowerOfTen`
- **Misc**
  - Added `AUTHORS.md`.

dlib 1.2.0 - 30 Apr, 2023
-------------------------
No changes since dlib 1.2.0 beta1.

dlib 1.2.0 beta1 - 19 Apr, 2023
-------------------------------
- **dlib.math**
  - `homothetyMatrix` and `homothetyMatrix2D` functions in `dlib.math.transformation`
  - `radtorev` and `revtorad` functions in `dlib.math.utils` that convert radians to revolutions and revolutions to radians, respectively
- **dlib.image**
  - New funtion `drawRect` in `dlib.image.render.shapes`
- **Misc**
  - Added `CODE_OF_CONDUCT.md`
  - Doxygen support for documentation.

dlib 1.1.0 - 5 Oct, 2022
-------------------------
No changes since dlib 1.1.0 beta1.

dlib 1.1.0 beta1 - 10 Sep, 2022
-------------------------------
- **dlib.geometry**
  - New module `dlib.geometry.mpr` - implementation of the Minkowski Portal Refinement algorithm that detects intersection between two arbitrary convex shapes
  - New module `dlib.geometry.support` with support functions for some common shapes
- **dlib.math**
  - `integer` and `frac` functions in `dlib.math.utils` that return integer part and fractional part of a real number, respectively.
- **dlib.image**
  - Fix compilation for x86.

dlib 1.0.0 - 17 Feb, 2022
-------------------------
No changes since dlib 1.0.0 beta2.

dlib 1.0.0 beta2 - 05 Feb, 2022
-------------------------------
Changes since dlib 1.0.0 beta1:
- **dlib.image**
  - File-based image loading functions now preload data to memory, so that decoders run faster (2x-10x depending on format and image size).

dlib 1.0.0 beta1 - 12 Jan, 2022
-------------------------------
- **dlib.core**
  - **Breaking change:** `dlib.core.bitio.swapEndian16` moved to `dlib.math.utils`
  - POSIX thread creation is now validated in debug mode
- **dlib.math**
  - **Breaking change:** deprecated method `Quaternion.generator` has been removed
  - **Breaking change:** deprecated functions `sum`, `invertArray`, `allIsZero` in `dlib.math.utils` have been removed
  - `interpHermiteDerivative`
  - `interpHermite` now support vector types
  - `Complexd` alias to `Complex!(double)` in `dlib.math.complex`
  - Fix `dlib.math.complex.pow`, `dlib.math.complex.atan2`
- **dlib.geometry**
  - **Breaking change:** deprecated method `Ray.intersectSphere` with `position` and `radius` arguments has been removed
  - **Breaking change:** deprecated method `Ray.intersectTriangle` with `v0`, `v1`, `v2` arguments has been removed.
  - Fix `Triangle.boundingBox`
  - New function `intrSphereVsAABB` in `dlib.geometry.intersection`
  - `AABB.intersectsSphere` is deprecated, use `intrSphereVsAABB` instead.

dlib 0.23.0 - 1 Oct, 2021
-------------------------
No changes since dlib 0.23.0 beta1.

dlib 0.23.0 beta1 - 28 Sep, 2021
--------------------------------
- **dlib.math**
  - Vector swizzling assign support: `v.zxy = Vector3f(1, 2, 3);`
  - `Quaternion.generator` is deprecated, use `Quaternion.rotationAxis` and `Quaternion.rotationAngle` instead
  - `Quaternion.fromEulerAngles` and `Quaternion.toEulerAngles` now use angles in pitch-yaw-roll format
  - `EPSILON` in `dlib.math.utils` now equals 0.000001.
- **dlib.geometry**
  - `Ray.intersectSphere` with `position` and `radius` arguments is deprecated, use `Ray.intersectSphere` with `Sphere` struct instead
  - `Ray.intersectTriangle` with `v0`, `v1`, `v2` arguments is is deprecated, use `Ray.intersectTriangle` with `Triangle` struct instead
- **dlib.image**
  - `isAlmostZero` for `Color4f`
- **dlib.filesystem**
  - `StdFileSystem.openDir` now returns null if path is not a valid directory.

dlib 0.22.0 - 13 Jun, 2021
--------------------------
No changes since dlib 0.22.0 beta1.

dlib 0.22.0 beta1 - 26 May, 2021
--------------------------------
- **dlib.core**
  - **Breaking change:** removed `dlib.core.oop.implements` (non-working function)
- **dlib.math**
  - Fix matrix subtraction
  - Fix wrong bounds check in matrix slice assignment
  - **Breaking change:** removed `dlib.math.linsolve.solveGS` (non-working function)
  - Binary matrix operations are now `const`
  - `sum`, `invertArray`, `allIsZero` in `dlib.math.utils` are deprecated. Use `reduce!((a, b) => a + b)`, `map!(a => -a)`, `reduce!((a, b) => a + b == 0)` instead
- **dlib.image**
  - **Breaking change:** deprecated type `dlib.image.image.PixelFormat` has been removed
  - **Breaking change:** deprecated aliases `save` and `load` in `dlib.audio.io` have been removed
- **dlib.audio**
  - **Breaking change:** deprecated aliases `save`, `load`, `saveAnimated`, `loadAnimated`, `saveHDRI`, `loadHDRI` in `dlib.image.io` have been removed
- **dlib.text**
  - **Breaking change:** deprecated method `UTF8Decoder.byDChar` have been removed
  - **Breaking change:** deprecated method `UTF16LEDecoder.byDChar` have been removed
  - **Breaking change:** deprecated aliases `UTF16Decoder` and `UTF16Encoder` have been removed
- **dlib.serialization**
  - Boolean values support in JSON decoder.

dlib 0.21.0 - 7 Apr, 2021
-------------------------
No changes since dlib 0.21.0 beta2.

dlib 0.21.0 beta2 - 28 Mar, 2021
--------------------------------
Changes since dlib 0.21.0 beta1:
- **dlib.image**
  - `PixelFormat` is deprecated, use `IntegerPixelFormat` instead.

dlib 0.21.0 beta1 - 22 Feb, 2021
--------------------------------
- **dlib.text**
  - **Breaking change:** deprecated module `dlib.text.unmanagedstring` has been removed
  - **Breaking change:** deprecated method `String.byDChar` has been removed
  - `UTF16Decoder` and `UTF16Encoder` are deprecated, use `UTF16LEDecoder` and `UTF16LEEncoder` instead
- **dlib.image**
  - **Breaking change:** deprecated module `dlib.image.io.io` has been removed
  - `load` and `save` are deprecated, use `loadImage` and `saveImage` instead
  - `loadAnimated` and `saveAnimated` are deprecated, use `loadAnimatedImage` and `saveAnimatedImage` instead
  - `loadHDRI` and `saveHDRI` are deprecated, use `loadHDRImage` and `saveHDRImage` instead
  - Fix integer overflow in `Image.getPixel` and `Image.setPixel`
- **dlib.container**
  - **Breaking change:** deprecated alias `DynamicArray` has been removed
- **dlib.coding**
  - **Breaking change:** deprecated module `dlib.coding.hash` has been removed
- **dlib.audio**
  - `load` and `save` are deprecated, use `loadSound` and `saveSound` instead
- **dlib.serialization**
  - Fix a bug in JSON decoder
- **Misc**
  - Switched from Travis CI to GitHub Actions for running integration tests.

dlib 0.20.0 - 16 Oct, 2020
--------------------------
No changes since dlib 0.20.0 beta1.

dlib 0.20.0 beta1 - 10 Oct, 2020
--------------------------------
- **dlib.image**
  - `dlib.image.io.io` is deprecated, import `dlib.image.io` instead
- **dlib.audio**
  - New package: `dlib.audio.io`
- **dlib.text**
  - `dlib.text.unmanagedstring` is deprecated, use `dlib.text.str` instead
  - `String.byDChar` is deprecated, use `String.decode` instead
  - `UTF8Decoder.byDChar` is deprecated, use `UTF8Decoder.decode` instead
  - `UTF16Decoder.byDChar` is deprecated, use `UTF16Decoder.decode` instead
- **dlib.coding**
  - `dlib.coding.hash` is deprecated, use `std.digest` instead
- **dlib.container**
  - `dlib.container.array.DynamicArray` is deprecated, use `dlib.container.array.Array` instead
- **Documentation**
  - Deploy-ready ddoc documentation for dlib now can be generated from source code using `dub --build=ddox`. It uses [scod](https://code.dlang.org/packages/scod) generator and is hosted [here](https://gecko0307.github.io/dlib/docs/dlib.html). Harbored-mod support has been dropped.
  - Many modules are now documented better.
- **Misc**
  - Added latest DMD (2.094.0, 2.093.1) and LDC (1.23.0) to Travis CI config.

dlib 0.19.2 - 26 Aug, 2020
--------------------------
- A couple of fixes for LDC
- New AppVeyor configuration.

dlib 0.19.1 - 24 July, 2020
---------------------------
- **dlib.network**
  - Fixed compilation under Windows
- **dlib.filesystem**
  - `isFile`, `isDir` properties now work for `StdFileSystem` entries
- **dlib.container**
  - `DynamicArray.readOnlyData`
- **dlib.text**
  - `String.toString` and `String.ptr` are now `const`
- **Misc**
  - Added latest DMD (2.093.0) and LDC (1.22.0) to Travis CI config.

dlib 0.19.0 - 31 May, 2020
--------------------------
Changes since beta2:
- **dlib.coding**, **dlib.filesystem**
  - Deprecation fixes
- **Misc**
  - Added latest DMD (2.092.0) to Travis CI config.

dlib 0.19.0 beta2 - 22 May, 2020
--------------------------------
Changes since beta1:
- **dlib.math**
  - Transformation of a vector with 4x4 matrix now doesn't include affinity check.
  - `dlib.math.transformation.scaling` fix.

dlib 0.19.0 beta1 - 8 May, 2020
-------------------------------
- **dlib.core**
  - New module `dlib.core.mutex`, a thin abstraction over platform-specific thread synchronization primitives.
  - `Thread.sleep`
- **dlib.concurrency**
  - New package that implements a simple thread pool.
- **dlib.image**
  - New module `dlib.image.render.text` that provides `drawText`, a function to render ASCII strings on images.
- **dlib.math**
  - **Breaking change:** deprecated modules `dlib.math.easing`, `dlib.math.smoothstep` have been removed.
  - **Breaking change:** tuple constructor of `Vector` now implicitly extends the last argument to all remaining components if the tuple is smaller than vector. This ensures e.g. `Vector3f(0) == Vector3f(0, 0, 0)`.
- **dlib.geometry**
  - **Breaking change:** deprecated modules `dlib.geometry.bezier`, `dlib.geometry.hermite` have been removed.
- **Breaking change:** deprecated package `dlib.functional` has been removed.
- **dlib.text**
  - `UTF16Encoder` in `dlib.text.utf16`.
  - `String` can now be constructed directly from `InputStream`.
  - **Breaking change:** deprecated property `String.cString` has been removed.
- **dlib.container**
  - `Queue` and `Stack` now use `DynamicArray` internally instead of `LinkedList`.
- **Misc**
  - Added latest DMD (2.091.1, 2.090.1) and LDC (1.21.0, 1.20.0) to Travis CI config.

dlib 0.18.0 - 28 Feb, 2020
--------------------------
No changes since dlib 0.18.0 beta1.

dlib 0.18.0 beta1 - 23 Feb, 2020
--------------------------------
- **dlib.math**
  - All interpolation functions moved to `dlib.math.interpolation`, which is now a package import. It includes `nearest`, `linear`, `bezier`, `catmullrom`, `hermite`, `smoothstep`, `easing` modules. Corresponding old modules (`dlib.math.easing`, `dlib.math.smoothstep`, `dlib.geometry.bezier`, `dlib.geometry.hermite`) are deprecated.
- **dlib.audio**
  - `SawtoothWaveSynth`, `TriangleWaveSynth` in `dlib.audio.synth`.
- **dlib.text**
  - `String` is now always null-terminated.
- **dlib.functional**
  - The whole package is now deprecated.
  - `dlib.functional.hof` module moved to `dlib.math.hof`.
  - `dlib.functional.range` module is deprecated, use `std.range.iota` instead.
- **Misc**
  - Added latest DMD (2.090.1, 2.089.1) and LDC (1.19.0, 1.18.0) to Travis CI config.

dlib 0.17.0 - 21 Oct, 2019
--------------------------
Changes since beta:
- **dlib.container**
  - `dlib.container.array`: iterating over array via `foreach_reverse`.

dlib 0.17.0 beta1 - 5 Oct, 2019
-------------------------------
- **dlib.core**
  - `BufferedStreamReader` in `dlib.core.stream` - a simple input range to read fixed chunks of data from an `InputStream`.
- **dlib.image**
  - **Breaking change:** `dlib.image.compleximage` has been removed.
  - `dlib.image.signal2d` is now fully GC-free.
  - Filtering of indexed images in PNG decoder is now supported (#142).
- **dlib.math**
  - `dlib.math.tensor` now uses `dlib.core.memory` for internal allocations.
  - **Breaking change:** deprecated function `identityQuaternion` has been removed. Use `Quaternion.identity` instead.
- **dlib.geometry**
  - **Breaking change:** deprecated aliases `bezierCurveFunc2D` and `bezierCurveFunc3D` have been removed. Use `bezierVector2` and `bezierVector3` instead.
- **Misc**
  - Added latest DMD (2.088.0, 2.087.1) and LDC (1.17.0, 1.16.0) to Travis CI config.

dlib 0.16.0 - 30 Mar, 2019
--------------------------
No changes since dlib 0.16.0 beta1.

dlib 0.16.0 beta1 - 4 Mar, 2019
-------------------------------
- **dlib.core**
  - `dlib.core.memory`: Memory profiler now reports file and line of each allocation. Now it is enabled in runtime using `enableMemoryProfiler` function.
  - `dlib.core.memory`: `Owner.deleteOwnedObject`.
- **dlib.text**
  - `dlib.text.lexer`: `Lexer.position`.
  - `dlib.text.unmanagedstring`: `String.cString`.
  - **Breaking change:** deprecated module `dlib.text.slicelexer` has been removed.
- **dlib.container**
  - `dlib.container.array`: `DynamicArray.removeFirst`.
  - **Breaking change:** deprecated module `dlib.container.hash` has been removed.
- **dlib.image**
  - **Breaking change:** deprecated module `dlib.image.parallel` has been removed.
- **dlib.math**
  - New module `dlib.math.easing` - some basic easing functions for fancy interpolation.
  - **Breaking change:** deprecated module `dlib.math.fixed` has been removed.
  - `dlib.math.quaternion`: fixed a bug in `Quaternion.rotationAxis`.
- **dlib.geometry**
  - `dlib.geometry.trimesh` not doesn't use GC.
- **dlib.serialization**
  - `dlib.serialization.json` - GC-free JSON parser.
- **dlib.functional**
  - **Breaking change:** deprecated module `dlib.functional.combinators`, `dlib.functional.quantifiers` has been removed.
  - **Breaking change:** deprecated `map`, `filter`, `reduce` functions from `dlib.functional.range` have been removed.
- **Misc**
  - Added latest DMD (2.085.0, 2.084.1) and LDC (1.13.0, 1.14.0) to Travis CI config.

dlib 0.15.0 - 9 Nov, 2018
-------------------------
- **dlib.container**
  - `opSlice` and `$` for `dlib.container.array.DynamicArray`.

dlib 0.15.0 beta1 - 4 Nov, 2018
-------------------------------
- **dlib.core**
  - **Breaking change**: temporarily removed `dlib.core.fiber` due to lacking Windows support. It is now in [fiber branch](https://github.com/gecko0307/dlib/tree/fiber) until finished.
- **dlib.text**
  - New module `dlib.text.unmanagedstring` that provides `String`, a GC-free UTF8 string type based on `DynamicArray`.
  - `UTF16Decoder` in `dlib.text.utf16`, `UTF8Encoder` in `dlib.text.utf8`.
  - `dlib.text.encodings` - a one-stop solution for handling text encodings in generic way. Decoder is any range that outputs `dchar`, encoder is any object that defines `size_t encode(dchar, ubyte[])`.
  - `dlib.text.common` that defines `DECODE_END` and `DECODE_ERROR` for decoders to use.
- **dlib.container**
  - `reserve` and `resize` for `dlib.container.array.DynamicArray` (#151).
  - **Breaking change**: deprecated `dlib.container.aarray` module has been removed. Use `dlib.container.dict` instead.
- **dlib.image**
  - Fixed unintentional fallthrough in `dlib.image.io.saveImage` that caused error on TGA image.
  - More accurate path filling in `dlib.image.canvas`.
  - `dlib.image.parallel` has been deprecated.
- **dlib.math**
  - **Breaking change**: deprecated `dlib.math.affine` module has been removed. Use `dlib.math.transformation` instead.
  - `dlib.math.fixed` has been deprecated.
- **dlib.functional**
  - `dlib.functional.quantifiers` has been deprecated.
  - Free functions in `dlib.functional.range` (`map`, `filter`, `reduce`) have been deprecated. Use corresponding Phobos functions instead.
- **Misc**
  - dlib now can be built with recent GNU D Compiler (GDC). **Note:** `dlib.math.sse` is not supported with GDC.
  - Added latest DMD (2.083.0, 2.082.1) and LDC (1.12.0) to Travis CI config.
  - Support for [harbored-mod](https://github.com/dlang-community/harbored-mod) documentation generator.

dlib 0.14.0 - 9 Jul, 2018
-------------------------
No changes since dlib 0.14.0 beta1.

dlib 0.14.0 beta1 - 8 Jul, 2018
-------------------------------
**Important:** dlib now officially doesn't support macOS. This is an act of protest against [Apple's drop of OpenGL support](https://developer.apple.com/macos/whats-new/#deprecationofopenglandopencl). While you probably still can use dlib's platform-independent and Posix-based functionality under macOS, there's no guarantee that this will continue, and compatibility issues will not be addressed. Read detailed manifesto [here](https://github.com/gecko0307/dlib/wiki/Why-dlib-doesn%27t-support-macOS%3F).

- **dlib.image**
  - **Breaking change:** `SuperImage.pixelFormat` now returns `uint` instead of `PixelFormat`. This allows extending dlib with custom pixel formats while maintaining compatibility with `PixelFormat`. Values from 0 to 255 are reserved for dlib, values 256 and above are application-specific. This change is just a new convention and will not break any existing logics, though explicit cast to `PixelFormat` may be required in some cases. Comparisons such as `img.pixelFormat == PixelFormat.RGB8` will work fine.
  - `PixelFormat.RGBA_FLOAT` is now deprecated, use `FloatPixelFormat.RGBAF32` from `dlib.image.hdri` instead.
  - Saving to HDR is now supported (`saveHDR` functions in `dlib.image.io.hdr`).
  - New filters: `dlib.image.filters.histogram` (generates an image histogram) and `dlib.image.filters.binarization` (image thresholding using Otsu's method).
  - ACES tonemapper (`hdrTonemapACES`) and average luminance function (`averageLuminance`) in `dlib.image.hdri`.
  - Improved `dlib.image.canvas`. Path rasterizer now natively does anti-aliasing. Fixed bug with rendering on non-square images.
- **dlib.audio**
  - Synthesizer framework (`dlib.audio.synth`). It allows to write synthesizers and use them to 'render' sounds, like in DAWs. Three built-in synthesizers are available: `SineWaveSynth`, `SquareWaveSynth`, `FMSynth`. To write actual data to `Sound` objects, two functions are available: `fillSynth` and `mixSynth`.
- **dlib.math**
  - New module `dlib.math.smoothstep` with sigmoid-like functions: `hermiteSmoothstep`, `rationalSmoothstep`.
- **dlib.core**
  - DMD 2.081.0 compatibility fix in `dlib.core.stream`.
- **Misc**
  - Added latest DMD (2.081.0, 2.080.1) and LDC (1.10.0) to Travis CI config. CI builds for macOS were stopped for reason mentioned above.

dlib 0.13.0 - 14 May, 2018
--------------------------
No changes since dlib 0.13.0 beta1.

dlib 0.13.0 beta1 - 9 May, 2018
-------------------------------
- **dlib.async** has been removed for security reasons. Currently there are no active contributors to maintain the package and fix bugs, so it is considered not safe to use due to potential data corruption or loss. There's [async branch](https://github.com/gecko0307/dlib/tree/async) for those who still want to use it, but for new projects it is strongly recommended to consider using more actively developed alternatives, such as [vibe-core](https://code.dlang.org/packages/vibe-core) or [Tanya](https://code.dlang.org/packages/tanya).
- **dlib.image**
  - New module `dlib.image.canvas` that provides `Canvas` class, a vector graphics engine inspired by HTML5 canvas. Currently it supports rasterizing arbitrary polygons and cubic Bezier paths, filled and outlined. It renders to user-provided `SuperImage`.
  - Improved HDR file decoder. Now it supports HDR files with magic string `#?RGBE`.
  - Reinhard and Hable tonemappers in `dlib.image.hdri`: `hdrTonemapReinhard` and `hdrTonemapHable`.
  - New filters in `dlib.image.filters.edgedetect`: `edgeDetectLaplace` and `edgeDetectSobel`.
  - New methods for `Color4f`: `toLinear` and `toGamma`.
  - Fixed bugs in `dlib.image.arithmetics` module.
- **dlib.math**
  - New functions in `dlib.math.vector`: `reflect`, `refract`, `faceforward`.
  - New functions in `dlib.math.utils`: `min2` and `max2`.
- **dlib.geometry**
  - New functions in `dlib.geometry.bezier`: `bezierTangentVector2` and `bezierTangentVector3`.
- **Misc**
  - Added latest DMD (2.080.0, 2.079.1) and LDC (1.9.0, 1.8.0) to Travis CI config.
  - dlib now does CI under Windows using [AppVeyor](https://www.appveyor.com/).

dlib 0.12.2 - 7 Nov, 2017
-------------------------
* Enum constants of type `Vector` now can be assigned to variables.
* Naming of functions in `dlib.geometry.bezier` is changed. `bezier` function is now `bezierCubic`, `bezierCurveFunc2D` is `bezierVector2`, `bezierCurveFunc3D` is `bezierVector3`. There are aliases with old names for backward compatibility.

dlib 0.12.1 - 28 Oct, 2017
--------------------------
* Fixed loading 16-bit PNG images
* Corrected Bézier function.

dlib 0.12.0 - 16 Oct, 2017
--------------------------
No changes since dlib 0.12.0 beta1.

dlib 0.12.0 beta1 - 9 Oct, 2017
-------------------------------
- **dlib.core**
  - New module `dlib.core.ownership` - a Delphi-like object ownership system. Objects are registered to parent object, which automatically deletes them when gets deleted itself. In many cases this can be a convenient trade-off between fully automatic and fully manual memory management.
  - New module `dlib.core.fiber` - initial fibers implementation (Linux-only for now).
- **dlib.container**
  - Containers now use Phobos-conforming method names. Old names are still supported via aliases.
  - `DynamicArray` now supports inserting and removing values by arbitrary indices (`insertKey` and `removeKey`).
  - `~=` operator support for `LinkedList`.
  - Full unittest coverage of `dlib.container.array`.
  - More unittests for `dlib.container.dict`.
- **dlib.image**
  - New class `UnmanagedAnimatedImage` - GC-free counterpart of `AnimatedImage`.
  - **Breaking change:** `dlib.image.tone.contrast` is now `dlib.image.filters.contrast`.
  - `dlib.image.fthread` is now based on `dlib.core.thread`.
- **dlib.filesystem**
  - File access rights in `FileStat`.
  - Nanosecond modification time precision support in `stat` under Posix.
- **dlib.math**
  - New direct solver (`solve`) in `dlib.math.linsolve` based on LUP decomposition.
- **dlib.geometry**
  - Frustum-sphere intersection test (`intersectsSphere`) for `dlib.geometry.frustum`.
- **dlib.coding**
  - **Breaking change:** `dlib.coding.huffman` is merged with `dlib.image.io.jpeg`.
- **Misc**
  - Added latest DMD (2.075.1, 2.076.0) and LDC (1.3.0, 1.4.0) to Travis CI config.

dlib 0.11.1 - 24 May, 2017
--------------------------
* Added `alphaOver` in `dlib.image.color`
* Fixed memory leak in `dlib.image.io.png`
* Deprecation fix: use `dlib.math.transformation` everywhere instead of `dlib.math.affine`.

dlib 0.11.0 - 3 May, 2017
-------------------------
Changes from beta:
* Merged `idct.d` with `jpeg.d`, use `dlib.math.transformation` in `dlib.image.transform`
* Added `hdrTonemapAverageLuminance` to `dlib.image.hdri`
* Fixed memory leak in HDR decoder

dlib 0.11.0 beta1 - 25 Apr, 2017
--------------------------------
- **dlib.core**
  - `New` and `Delete` in `dlib.core.memory` are now based on allocators from `dlib.memory`. By default `Mallocator` is used. It is possible to switch global allocator.
- **dlib.memory**
  - Added `GCallocator`, an allocator based on on D's built-in garbage collector.
- **dlib.image**
  - Full-featured APNG support in `dlib.image.io.png` with dispose and blend operations. Saving animations to APNG is also supported.
- **dlib.filesystem**
  - Added `traverseDir`, GC-free recursive directory scanner.
- **dlib.math**
  - `distance` and `distancesqr` overloads for 2D vectors.
  - `dlib.math.affine` is now deprecated. `dlib.math.transformation` should be used instead.
- **dlib.async**
  - Fixed segfault in event loop.
- **Misc**
  - Removed deprecated `dlib.xml` package. `dlib.serialization.xml` should be used instead.
  - Added latest DMD (2.074.0) and LDC (1.2.0) to Travis CI config.
  - A new logo and homepage for the project: https://gecko0307.github.io/dlib.

dlib 0.10.1 - 14 Mar, 2017
--------------------------
* Animated images and basic APNG support (unfinished, without dispose and blend operations, saving to APNG is also missing)
* Fixed some bugs in `dlib.text.slicelexer` and `dlib.serialization.xml`. `dlib.text.lexer.Lexer` is now an alias to `dlib.text.slicelexer.SliceLexer`
* Added latest DMD (2.073.2) and LDC (1.1.0) to Travis CI config.

dlib 0.10.0 - 23 Jan, 2017
--------------------------
Changes from beta:
- 64-bit fix in `dlib.network.socket` under Windows
- Unittest fix in `dlib.filesystem.local`
- Code cleanup, use consistent line endings and indentations everywhere
- EditorConfig support
- dlib now compiles with DMD 2.073.0 and LDC 1.1.0-beta6.

dlib 0.10.0 beta1 - 13 Jan, 2017
--------------------------------
- **dlib.async** - this new package provides a cross-platform event loop and asynchronous programming capabilities. It can be used to implement asynchronous servers. Under the hood the package is based on different multiplexing APIs: Epoll on Linux, IOCP on Windows, and Kqueue on BSD / OSX
- **dlib.memory** - new tools and interfaces to generalize memory allocation. There is `Allocator` interface, similar to Phobos' `IAllocator`, but simpler. There are also several implementations of this interface: `Mallocator` (malloc based allocator) and `MmapPool` (block based allocator for Posix systems with mmap/munmap support).
- **dlib.serialization** - a new home for XML (and, hopefully, other markup languages in future). `dlib.xml` is deprecated, but left with public imports for compatibility purpose
  - XML parser (`dlib.serialization.xml`) is now fully GC-free
- **dlib.network**
  - `dlib.network.socket`, a cross-platform socket API. Supports Windows and Posix
- **dlib.image**
  - Breaking change: redesign of `dlib.image.hdri` module. Now it supports manual memory allocation and has its own image factories. Also implemented simple tone mapping tool based on gamma compression to convert HDR images to LDR
  - Radiance HDR/RGBE format support (only loading for now)
- **dlib.container**
  - New module - `dlib.container.buffer`, an interface for input/output buffers
  - Fixed some issues in `dlib.container.array`
- **dlib.text**
  - Improved `SliceLexer` (fixed bug with multicharacter delimiters)
  - Added `dlib.text.utils.immutableCopy`
- **dlib.math**
  - `dlib.math.vector.normal` is now `dlib.math.vector.planeNormal`
- **Other improvements**
  - Added latest DMD (2.072.2) to Travis CI config.

Many thanks to [Eugene Wissner](https://github.com/belka-ew) for implementing `dlib.async`, `dlib.memory` and `dlib.network`.

dlib 0.9.2 - 11 Jun, 2016
-------------------------
- Fixed building with DMD 2.071.1

dlib 0.9.1 - 9 Jun, 2016
------------------------
- Added `SliceLexer` in `dlib.text`
- Fixed wrong `opApply` in `DynamicArray` and `Trie`

dlib 0.9.0 - 23 May, 2016
-------------------------
Changes from beta:
- Bugfix and unittests for `ArrayStream`
- Fixed loading of 32-bit BMP with bitfield masks.

dlib 0.9.0 beta1 - 14 May, 2016
-------------------------------
- dlib.network
  - A new package for networking. So far it contains only one module, `dlib.network.url` - an URL parser
- dlib.image
  - 2-dimensional iteration for images. Also there are now `ImageRegion` and `ImageWindowRange` that simplify writing kernel filters
  - `dlib.image.transform` module implements affine transformations for images: translation, rotation and scaling. Transformation with arbitrary 3x3 matrix is also possible
  - Improved BMP and TGA support: new color modes and RLE8 for BMP, saving BMP and TGA
  - Improved `boxBlur`
  - `getPixel` and `setPixe` in `Image` class are now public
- dlib.math
  - New `dlib.math.tensor` module implements generic multidimensional array, both with static and dynamic memory allocation
- dlib.container
  - Improved `LinkedList`, added range interface. Added unittests for `LinkedList` and `DynamicArray`
- dlib.text
  - `UTF8Decoder` and `Lexer` now support range interface. Added unittests for both
- Other improvements
  - Added latest DMD (2.071.0) to Travis CI config, added DUB service files to .gitignore.

dlib 0.8.1 - 13 Feb, 2016
-------------------------
Minor bugfix release: `saveWav` in `dlib.audio.io.wav` now uses `Sound` interface instead of `GenericSound` class.

dlib 0.8.0 - 12 Feb, 2016
-------------------------
Changes from beta:
* Fixed #87

dlib 0.8.0 beta1 - 7 Feb, 2016
------------------------------
* dlib.audio
  * `dlib.audio` is a new package for audio processing. Supports 8 and 16 bits per sample, arbitrary sample rate and number of channels. Includes generic sound interfaces (in-memory and streamed) and their implementations. Read more [here](https://github.com/gecko0307/dlib/wiki/dlib.audio).
  * `dlib.audio.synth` implements some basic sound synthesizers (sine wave and white noise)
  * `dlib.audio.io.wav` - uncompressed RIFF/WAV encoder and decoder
* dlib.image
  * All image filters, arithmetic operations, etc. now support manual memory management
  * New chroma key filter based on Euclidean distance (`dlib.image.filters.chromakey.chromaKeyEuclidean`)
  * New edge detection filter based on morphological gradient (`dlib.image.filters.edgedetect.edgeDetectGradient`)
  * Several important bugfixes (image convolution, lanczos and bicubic resampling, wrong deallocation of empty JPEGImage)
* dlib.core
  * Fixed erroneous deleting uninitialized thread in `dlib.core.thread`
* dlib.filesystem
  * Implemented missing methods in `dlib.filesystem.stdfs.StdFileSystem`: `openForIO`, `openDir`, `createDir`, `remove`. There is a known issue with `remove`: it doesn't delete directories under Windows
* Other improvements
  * Added [HTML documentation generator](https://github.com/gecko0307/dlib/tree/master/gendoc).

dlib 0.7.1 - 2 Dec, 2015
------------------------
Mostly bugfix release.
* Fixed wrong iteration of `dlib.container.dict.Trie`
* `_allocatedMemory` in `dlib.core.memory` is now marked as `__gshared`, thus working correctly with `dlib.core.thread`
* Fixed wrong behaviour of `nextPowerOfTwo` in `dlib.math.utils`
* Ambiguous `rotation` functions in `dlib.math.affine` and `dlib.math.quaternion` are renamed into `rotation2D` and `rotationQuaternion`, respectively
* Added `flatten` method for matrices.

dlib 0.7.0 - 2 Oct, 2015
------------------------
Changes from beta:
* Fixed 64-bit issues
* dlib now compiles with latest LDC
* Continuous integration using Travis-CI: https://travis-ci.org/gecko0307/dlib

dlib 0.7.0 beta1 - 28 Sep, 2015
-------------------------------
* dlib.core
  * Added GC-free, Phobos-independent thread module - `dlib.core.thread`
* dlib.text
  * A new package for GC-free text processing. Includes UTF-8 decoder (`dlib.text.utf8`) and general-purpose lexical analyzer (`dlib.text.lexer`)
* dlib.xml
  * XML parser is now GC-free and based on `dlib.text.lexer`
* dlib.container
  * Added GC-free LinkedList (`dlib.container.linkedlist`), Stack (`dlib.container.stack`), Queue (`dlib.container.queue`)
* dlib.image
  * Fixed segfault with non-transparent indexed PNG loading
* dlib.math
  * Fixed error with instancing of vectors with size larger than 4
* Other improvements
  * Added Travis-CI support

dlib 0.6.4 - 14 Sep, 2015
-------------------------
* Trie-based GC-free dictionary class (`std.container.dict`)
* Several performance optimizations in `dlib.math`: vector element access and multiplication for 3x3 and 4x4 matrices are now faster
* Fixed some 64-bit issues.

dlib 0.6.3 - 17 Aug, 2015
-------------------------
* Fixed `dlib.filesystem.stdfs` compilation under 64-bit systems
* Fixed PNG exporter bug with encoding non-compressible images
* Added basic drawing functions (`dlib.image.render.shapes`)

dlib 0.6.2 - 20 Jul, 2015
-------------------------
Bugfix release.
* Removed coordinates clamping on pixel write in dlib.image
* Fixed bug with PNG vertical flipping

dlib 0.6.1 - 6 Jul, 2015
------------------------
* Added memory profiler
* Fixed `dlib.math.sse` compilation on 64-bit systems

dlib 0.6.0 - 24 Jun, 2015
-------------------------
* dlib.core
  * Got rid of ManuallyAllocatable interface in manual memory management for classes. Added support for deleting via interface or parent class. Deleting can be abstractized with Freeable interface
* dlib.filesystem
  * Added GC-free implementations for FileSystem and file streams
* dlib.image
  * dlib.image.unmanaged provides generalized GC-free Image class with corresponding factory function
  * JPEG decoder had been greatly improved, added more subsampling modes support, COM and APPn markers detection. Decoder now understands virtually any imaginable baseline JPEGs, including those from digital cameras
* dlib.math
  * New module dlib.math.combinatorics with factorial, hyperfactorial, permutation, combinations, lucas number and other functions
  * dlib.math.sse brings x86 SSE-based optimizations for some commonly used vector and matrix operations, namely, 4-vector arythmetics, dot and cross product, 4x4 matrix multiplication.
* dlib.container
  * DynamicArray now supports indexing (as a syntactic sugar).

dlib 0.5.3 - 5 May, 2015
-----------------------
* Added Protobuf-style varint implementation (dlib.coding.varint)
* Streams are now ManuallyAllocatable
* Triangle struct in dlib.geometry.triangle now has tangent vectors
* Fixed unittest build failure (#59)

dlib 0.5.2 - 25 Feb, 2015
-------------------------
* Automated vector type conversion (#57), modulo operator for vectors (#58)
* Fixed warning in dlib.image.io.bmp (#56)

dlib 0.5.1 - 21 Feb, 2015
-------------------------
Small bugfix release:
* Fixed wrong module name in dlib.geometry.frustum
* Updated license information

dlib 0.5.0 - 20 Feb, 2015
-------------------------
* dlib.core
  * Added manual memory management support. dlib.core.memory provide memory allocators based on standard C malloc/free. They can allocate arrays, classes and structs
  * Added prototype-based OOP system for structs (dlib.core.oop) with support for multiple inheritance and parametric polymorphism
* dlib.image
  * Image loaders are now GC-free
  * dlib.image.io.zlib and dlib.image.io.huffman modules are moved to new package dlib.coding. dlib.image.io.bitio moved to dlib.core.
  * Image allocation is based on a factory interface that abstracts over GC or MMM
  * Improved support for indexed PNGs - added alpha channel support
* dlib.container
  * Added GC-free dynamic array implementation (dlib.container.array)
  * BST and AArray now use manual memory management
* dlib.math
  * Quaternion is now based on and interchangeable with Vector via incapsulation
  * Dual quaternion support (dlib.math.dualquaternion)
  * Fixed incorrect dual number `pow` implementation
* dlib.geometry
  * Breaking change: Frustum plane normals are now pointing outside frustum. Also Frustum-AABB intersection API is changed
  * Fixed bugs in AABB and Plane

dlib 0.4.1 - 30 Dec, 2014
-------------------------
* dlib.image
  * Baseline JPEG decoder (dlib.image.io.jpeg)
* dlib.math
  * New matrix printer with proper alignment (a la Matlab)

dlib 0.4.0 - 27 Oct, 2014
-------------------------
* dlib.filesystem
  * Platform-specific modules are now grouped by corresponding packages (dlib.filesystem.windows, dlib.filesystem.posix)
  * `findFiles` is now a free function and can be used with any `ReadOnlyFileSystem`
* dlib.math
  * Implemented LU decomposition for matrices (dlib.math.decomposition)
  * `dlib.math.linear` is now `dlib.math.linsolve`. Added `solveLU`, a new LU-based direct solver
  * Matrix inversion now uses LU decomposition by default (4x performance boost compared to old analytic method). 4x4 affine matrices use an optimized inversion, which is about 6 times faster
  * `dlib.math.utils` now uses `clamp` from latest Phobos if available
  * Removed deprecated functionality
* dlib.core:
  * Moved container modules (bst, linkedlist, etc) from dlib.core to separate package dlib.container. Removed useless dlib.core.method
* Overall: improved compatibility with DMD 2.067.

dlib 0.3.3 - 31 Jul, 2014
-------------------------
Mainly bugfix release. Changes:
* Fixed compilation with DMD 2.066
* Added dlib.geometry.frustum
* Improved dlib.math.quaternion

dlib 0.3.2 - 11 Jun, 2014
-------------------------
Bugfix release. The main improvement is fixed compilation with some versions of LDC.

dlib 0.3.1 - 13 May, 2014
-------------------------
Bugfix release. Changes:
* Improved dlib.image, added interpolated pixel reading
* Added matrix addition and subtraction, tensorProduct now works with any matrix sizes
* Addressed many bugs in dlib.image and dlib.math.

dlib 0.3.0 - 25 Mar, 2014
-------------------------
* dlib.core
  * Added simple yet robust I/O streams (dlib.core.stream), which are completely Phobos-independent
* dlib.filesystem
  * Abstract FS interface and it's implementations for Windows and POSIX filesystems
* dlib.image
  * Breaking change: all pixel I/O is now floating-point (via `Color4f`). This gives an opportunity to define image classes of arbitrary floating-point pixel formats and enables straightforward HDRI: sample 32-bit implementation provided in dlib.image.hdri
  * Pixel iteration now can be done with `row` and `col` ranges
  * Parallel filtering is now easy with dlib.image.parallel. You can add multithreading to your existing filter code with just a few changes
  * Added support for TGA and BMP formats (only loading for now)
  * All image format I/O is now stream-based
* dlib.math
  * Breaking change: matrices in dlib.math.matrix are now column-major
  * Imporved constness support in dlib.math.vector, as well as added unittest to the module. Using new string constructor, vectors now can be parsed from strings (e.g., `"[0, 1, 2]"`)
* Overall improvements & bugfixes
  * Much saner DUB support, addressed some serious problems with building, added configuration for pre-compiling as a static library

dlib 0.2.4 - 12 Dec, 2013
-------------------------
Bugfix release + added support for DMD 2.064 package modules.

dlib 0.2.3 - 6 Dec, 2013
------------------------
Bugfix release. Fixed issues with compiling on 64-bit systems.

dlib 0.2.1 - 20 Nov, 2013
-------------------------
Bugfix release.

dlib 0.2.0 - 11 Oct, 2013
-------------------------
* Added XML parser (alpha quality);
* Massive refactoring of the matrix implementation. All matrix types (Matrix2x2f, Matrix3x3f, Matrix4x4f) are now specializations of generic Matrix!(T,N) struct in dlib.math.matrix;
* Updated dlib.math.dual. Vectors of dual numbers can now be created;
* Added support for Hermite curves (dlib.geometry.hermite).

dlib 0.1.2 - 18 Jul, 2013
-------------------------
* Renamed ColorRGBA and ColorRGBAf into Color4 and Color4f;
* Added support for image convolution. There are several built-in kernels (Identity, BoxBlur, GaussianBlur, Sharpen, Emboss, EdgeEmboss, EdgeDetect, Laplace);
* Added support for HSV color space;
* Added Chroma Keying and Color Pass filters.

dlib 0.1.1 - 13 Jul, 2013
-------------------------
Bugfix release.

dlib 0.1.0 - 13 Jul, 2013
-------------------------
Initial release.

13 Jul, 2013
------------
Project moved to GitHub.

2012-2013
---------
Early development on code.google.com.

28 Sep, 2012
------------
Start as a public project.


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct

This project welcomes contributions in any form and encourages open discussion and exchange of views on its features, architecture, and implementation details. To maintain a proper culture of communication, this Code of Conduct has been formulated. It applies to the project's issue tracker, chat, and possibly other communication channels.

1. We do not tolerate obscene language, insulting, rude and/or disparaging messages, the use of sexualized, violent and otherwise offensive speech and imagery.
2. Any criticism should be constructive and reasonable. Mere personal discontent without any objective reasoning is not enough to make critical statements and influence the development of dlib.
3. This project stays away from non-technological issues and topics. We welcome everyone, regardless of age, gender identity, religion, ethnicity, citizenship, or cultural background, and our community do not conduct any specific ideology. Sites, repositories, communication channels and other resources associated with dlib should not be used as a platform for propaganda.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines

#### Bug reporting 

Open an issue at [GitHub issue tracker](https://github.com/gecko0307/dlib/issues). Before doing that, ensure the bug was not already reported or fixed in `master` branch. Describe a problem and, if necessary, provide minimal code needed to reproduce it.

Note that macOS compatibility issues are not considered bugs. dlib intentionally doesn't support macOS anymore. Read more [here](https://github.com/gecko0307/dlib/wiki/Why-doesn't-dlib-support-macOS).

Bugs that have not been reproduced or discussed for 6 months or longer are marked as `wontfix` and closed.

We also use several other labels:
* Breaking change. Self-descriptive: an improvement that breaks backward compatibility
* Bug. A bug that should be fixed without API change
* Enhancement. A non-breaking improvement of existing functionality (optimization or a new feature)
* Missing. Appears when existing functionality is removed due to regressions and needs to be rewritten, or when some implementation is not complete
* New functionality. Self-descriptive: a new functionality request.

#### Bug fixing 

Open a new GitHub pull request with your patch. Provide a description of the problem and solution. Follow our [code style](#code-style-and-standards). Please, try to avoid solutions that break library API and semantics - such changes should be made very carefully. If the problem can't be solved without breaking changes, explicitly state that in the description.

#### Implementing new features 

Before writing a new module, familiarize yourself with [project philosophy](https://github.com/gecko0307/dlib/wiki/Rationale) and [best practices](https://github.com/gecko0307/dlib/wiki/Best-Practices). Despite being a general-purpose library, dlib is not a place for rarely used or too domain-specific code. In most cases it's better to start a new library instead of pushing new modules to dlib. Only in case you find yourself constantly reusing some generic functionality in different projects it may be reasonable to propose such code to dlib. It may be a data structure, sorting algorithm, data compression method, image file decoder, communication protocol, or anything of that sort.

New code should at least:
* work under Windows and POSIX systems and provide platform-agnostic API
* support x86 and x86_64 targets
* not rely on third party libraries other than system API
* follow dlib's [code style](#code-style-and-standards)
* use transparent dynamic memory allocations. Ideally the code should not allocate at all or rely on user for that. If internal dynamic allocations can't be avoided, they should be done with `dlib.core.memory` or `dlib.memory`. Direct garbage collector usage is discouraged
* follow [dlib's best practices](https://github.com/gecko0307/dlib/wiki/Best-Practices), making use of ownership, containers, streams, exceptionless error handling and filesystem abstraction
* not violate copyright/licensing. When adapting third-party code, make sure that it is compatible with [Boost Software License 1.0](https://www.boost.org/LICENSE_1_0.txt).

#### Code style and standards

dlib follows [D style](https://dlang.org/dstyle.html). Essential rules are the following:
* Use spaces instead of tabs. Each indentation level is 4 spaces
* Opening curly bracket should be on a new line (Allman style)
* Functions and variables should be in `camelCase`
* Types, constants and enums should be in `PascalCase`
* Module names should be in lowercase.

All modules in dlib should belong to a package (`dlib.core`, `dlib.math`, `dlib.image`, etc.). Keep package and module names short and informative. Modules with related functionality can be combined to subpackages (such as `dlib.image.io`). Provide a package import module (`package.d` with public imports) for each subpackage.

Each D module should start with a Boost license block prepended with a copyright notice:
```d
/*
Copyright (c) 2026 <author's name here>

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
```

#### Documenting

It is not strictly necessary to document code, but if you do, use [ddoc syntax](https://dlang.org/spec/ddoc.html). Each documented module should be accompanied by a description block (if you don't do that, documentation generators may ignore the module):
```d
/**
 * <One-line description of the module>
 *
 * Description:
 * <more in-depth information (optional)>
 *
 * Copyright: Your Name 2026.
 * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Your Name
 */
module dlib.something.something;
```

#### Testing

It is advisable to write unit tests for new code, if they can be written. Sometimes functionality needs particular external environment or special conditions to run; in these cases tests are not required.

It is recommended to add one `unittest` block per function, method, or class. Test block should be formatted in the following way:

```d
///
unittest
{
}
```


================================================
FILE: COPYING.md
================================================
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


================================================
FILE: Doxyfile
================================================
DOXYFILE_ENCODING      = UTF-8
PROJECT_NAME           = "dlib"
PROJECT_NUMBER         = 1.1
PROJECT_BRIEF          = "Allocators, I/O streams, math, geometry, image and audio processing for D"
PROJECT_LOGO           = "logo/dlib-logo-doxygen.png"
OUTPUT_DIRECTORY       = "docs-doxygen"
CREATE_SUBDIRS         = YES
CREATE_SUBDIRS_LEVEL   = 8
ALLOW_UNICODE_NAMES    = NO
OUTPUT_LANGUAGE        = English
GENERATE_HTML          = YES
HTML_OUTPUT            = html
HTML_FILE_EXTENSION    = .html
GENERATE_HTMLHELP      = YES
CHM_FILE               = "documentation.chm"
INPUT                  = "dlib"
RECURSIVE              = YES


================================================
FILE: README.md
================================================
<img align="left" alt="dlib logo" src="https://github.com/gecko0307/dlib/raw/master/logo/dlib-logo.png" height="66" />

dlib is a high-level general purpose library written in [D language](https://dlang.org) for game and graphics developers. It provides basic building blocks for writing real-time and multimedia applications: containers, data streams, linear algebra and image decoders.

dlib has no external dependencies aside D's standard library. dlib is created and maintained by [Timur Gafarov](https://github.com/gecko0307).

[![GitHub Actions CI Status](https://github.com/gecko0307/dlib/workflows/CI/badge.svg)](https://github.com/gecko0307/dlib/actions?query=workflow%3ACI)
[![DUB Package](https://img.shields.io/dub/v/dlib.svg)](https://code.dlang.org/packages/dlib)
[![DUB Downloads](https://img.shields.io/dub/dm/dlib.svg)](https://code.dlang.org/packages/dlib)
[![License](http://img.shields.io/badge/license-boost-blue.svg)](http://www.boost.org/LICENSE_1_0.txt)
[![Codecov](https://codecov.io/gh/gecko0307/dlib/branch/master/graph/badge.svg)](https://codecov.io/gh/gecko0307/dlib)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gecko0307/dlib?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

If you like dlib, please support its development on [Patreon](https://www.patreon.com/gecko0307) or [Liberapay](https://liberapay.com/gecko0307). You can also make one-time donation via [NOWPayments](https://nowpayments.io/donation/gecko0307). I appreciate any support. Thanks in advance!

What's inside
-------------
Currently dlib consists of the following packages:
* [dlib.core](https://gecko0307.github.io/dlib/docs/dlib/core.html) - basic functionality used by other modules (memory management, streams, threads, etc.)
* [dlib.container](https://gecko0307.github.io/dlib/docs/dlib/container.html) - generic data structures (GC-free dynamic and associative arrays and more)
* [dlib.filesystem](https://gecko0307.github.io/dlib/docs/dlib/filesystem.html) - abstract FS interface and its implementations for Windows and POSIX filesystems
* [dlib.math](https://gecko0307.github.io/dlib/docs/dlib/math.html) - linear algebra and numerical analysis (vectors, matrices, quaternions, linear system solvers, interpolation functions, etc.)
* [dlib.geometry](https://gecko0307.github.io/dlib/docs/dlib/geometry.html) - computational geometry (ray casting, primitives, intersection, etc.)
* [dlib.image](https://gecko0307.github.io/dlib/docs/dlib/image.html) - image processing (8-bit, 16-bit and 32-bit floating point channels, common filters and convolution kernels, resizing, FFT, HDRI, animation, graphics formats I/O: JPEG, PNG/APNG, BMP, TGA, HDR)
* [dlib.audio](https://gecko0307.github.io/dlib/docs/dlib/audio.html) - sound processing (8 and 16 bits per sample, synthesizers, WAV export and import)
* [dlib.network](https://gecko0307.github.io/dlib/docs/dlib/network.html) - networking and web functionality
* [dlib.memory](https://gecko0307.github.io/dlib/docs/dlib/memory.html) - memory allocators
* [dlib.text](https://gecko0307.github.io/dlib/docs/dlib/text.html) - text processing, GC-free strings, Unicode decoding and encoding
* [dlib.serialization](https://gecko0307.github.io/dlib/docs/dlib/serialization.html) - data serialization (XML and JSON parsers)
* [dlib.random](https://gecko0307.github.io/dlib/docs/dlib/random.html) - random number generation
* [dlib.coding](https://gecko0307.github.io/dlib/docs/dlib/coding.html) - various data compression and coding algorithms
* [dlib.concurrency](https://gecko0307.github.io/dlib/docs/dlib/concurrency.html) - a thread pool.

Supported Compilers
-------------------
dlib is automatically tested for compatibility with latest releases of DMD and LDC. Older releases formally are not supported, but in practice usually are, to some extent. There's no guaranteed support for GDC and other D compilers.

Documentation
-------------
HTML documentation can be generated from source code using ddox (run `dub build -b ddox`) or Doxygen (run `doxygen`). Be aware that documentation is currently incomplete.

* [Autogenerated documentation](https://gecko0307.github.io/dlib/docs/dlib.html)
* [Wiki](https://github.com/gecko0307/dlib/wiki)
* [Rationale](https://github.com/gecko0307/dlib/wiki/Rationale)
* [FAQ](https://github.com/gecko0307/dlib/wiki/FAQ)
* [Best Practices](https://github.com/gecko0307/dlib/wiki/Best-Practices)
* [Contributing Guidelines](https://github.com/gecko0307/dlib/blob/master/CONTRIBUTING.md)
* [Gitter chat room](https://gitter.im/gecko0307/dlib)

License
-------
Copyright (c) 2011-2026 Timur Gafarov, Martin Cejp, Andrey Penechko, Vadim Lopatin, Nick Papanastasiou, Oleg Baharev, Roman Chistokhodov, Eugene Wissner, Roman Vlasov, Basile Burg, Valeriy Fedotov, Ferhat Kurtulmuş, João Lourenço, Ate Eskola, Aaron Nédélec, Alexander Perfilyev. Distributed under the Boost Software License, Version 1.0 (see accompanying file COPYING or at https://www.boost.org/LICENSE_1_0.txt).

Sponsors
--------
Jan Jurzitza (WebFreak), Daniel Laburthe, Rafał Ziemniewski, Kumar Sookram, Aleksandr Kovalev, Robert Georges, Rais Safiullin (SARFEX), Benas Cernevicius, Koichi Takio, Konstantin Menshikov.

Users
-----
* [Dagon](https://github.com/gecko0307/dagon) - 3D game engine for D
* [Electronvolt](https://github.com/gecko0307/electronvolt) - work-in-progress first person puzzle game
* [DagoBan](https://github.com/Timu5/dagoban) - Sokoban clone
* [DlangUI](https://github.com/buggins/dlangui) - native UI toolkit for D
* [rengfx](https://github.com/xdrie/rengfx) - game engine based on raylib
* [Voxelman](https://github.com/MrSmith33/voxelman) - voxel-based game engine
* [RIP](https://github.com/LightHouseSoftware/rip) - image processing and analysis library by LightHouse Software
* [GeneticAlgorithm](https://github.com/Hnatekmar/GeneticAlgorithm) - genetic algorithms library
* [Orb](https://github.com/claudemr/orb) - a game/engine with procedural content
* [Leptbag](https://github.com/thotgamma/LeptbagCpp) - physics simulator by Gamma-Lab. Written in C++, but supports D plugins
* [aoynthesizer](https://github.com/AODQ/aoynthesizer) - sound synthesizer based on Lisp-like scripting language
* [D-VXLMapPreview](https://github.com/rakiru/D-VXLMapPreview) - isometric preview generator for Ace of Spades and Iceball maps
* [SMSFontConverter](https://github.com/Doom2fan/SMSFontConverter) - a program for generating Sega Master System fonts
* [sacengine](https://github.com/tg-2/sacengine/) - engine reimplementation for the game Sacrifice
* [Shaders Playground](https://github.com/AntonC9018/shader_playground) - a sandbox project for experimenting with OpenGL shaders
* [wgpu-dlang](https://github.com/gecko0307/wgpu-dlang) - WebGPU usage example.


================================================
FILE: dlib/audio/io/package.d
================================================
/*
Copyright (c) 2022-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Copyright: Timur Gafarov 2022-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.io;

import std.path: extension;
import dlib.audio.sound;

public
{
    import dlib.audio.io.wav;
}

class SoundLoadException: Exception
{
    this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
    {
        super(msg, file, line, next);
    }
}

/**
 * Saves a sound to file, selects encoder by filename extension
 */
void saveSound(GenericSound snd, string filename)
{
    switch(filename.extension)
    {
        case ".wav", ".WAV":
            snd.saveWAV(filename);
            break;
        default:
            assert(0, "Sound I/O error: unsupported sound format or illegal extension");
    }
}

/**
 * Loads sound from a file, selects decoder by filename extension
 */
GenericSound loadSound(string filename)
{
    switch(filename.extension)
    {
        case ".wav", ".WAV":
            return loadWAV(filename);
        default:
            assert(0, "Sound I/O error: unsupported sound format or illegal extension");
    }
}


================================================
FILE: dlib/audio/io/wav.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Uncompressed RIFF/WAV encoder and decoder
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.io.wav;

//version = WAVDebug; // Uncomment to see debug messages

version(WAVDebug)
{
    import std.stdio;
}
import dlib.core.memory;
import dlib.core.stream;
import dlib.filesystem.local;
import dlib.audio.sample;
import dlib.audio.sound;

/**
 * Simple RIFF/WAV decoder. Decodes WAV from stream using provided sound factory
 */
GenericSound loadWAV(InputStream istrm, GenericSoundFactory gsf)
{
    char[4] magic;
    istrm.fillArray(magic);
    assert(magic == "RIFF");

    int chunkSize;
    istrm.readLE(&chunkSize);
    version(WAVDebug)
    {
        writeln(chunkSize);
    }

    char[4] format;
    istrm.fillArray(format);
    version(WAVDebug)
    {
        writeln(format);
    }
    assert(format == "WAVE");

    char[4] fmtSubchunkID; // fmt
    istrm.fillArray(fmtSubchunkID);

    int fmtSubchunkSize;
    istrm.readLE(&fmtSubchunkSize);

    short audioFormat;
    short numChannels;
    int sampleRate;
    int byteRate;
    short blockAlign;
    short bitsPerSample;

    istrm.readLE(&audioFormat);
    istrm.readLE(&numChannels);
    istrm.readLE(&sampleRate);
    istrm.readLE(&byteRate);
    istrm.readLE(&blockAlign);
    istrm.readLE(&bitsPerSample);

    version(WAVDebug)
    {
        writefln("Format: %s", audioFormat);
        writefln("Number of channels: %s", numChannels);
        writefln("Sample rate: %s Hz", sampleRate);
        writefln("Byte rate: %s", byteRate);
        writefln("Block align: %s", blockAlign);
        writefln("Bits per sample: %s", bitsPerSample);
    }

    char[4] dataSubchunkID; // data
    istrm.fillArray(dataSubchunkID);

    int dataSubchunkSize;
    istrm.readLE(&dataSubchunkSize);
    version(WAVDebug)
    {
        writeln(dataSubchunkSize);
    }
    int numSamples = dataSubchunkSize / (numChannels * bitsPerSample/8);
    version(WAVDebug)
    {
        writefln("Number of samples: %s", numSamples);
        writefln("Duration: %s", (cast(float)numSamples) / sampleRate);
    }

    SampleFormat f;
    if (bitsPerSample == 8)
    {
        f = SampleFormat.U8;
    }
    else if (bitsPerSample == 16)
    {
        f = SampleFormat.S16;
    }

    GenericSound gs;
    gs = gsf.createSound(
        dataSubchunkSize,
        numSamples,
        (cast(double)numSamples) / sampleRate,
        numChannels,
        sampleRate,
        bitsPerSample,
        f
    );
    istrm.fillArray(gs.data);

    return gs;
}

/**
 * Decodes WAV from stream using default sound factory
 */
GenericSound loadWAV(InputStream istrm)
{
    return loadWAV(istrm, defaultGenericSoundFactory);
}

/**
 * Decodes WAV from file
 */
GenericSound loadWAV(string filename)
{
    auto istrm = openForInput(filename);
    ubyte[] data = New!(ubyte[])(cast(size_t)istrm.size);
    istrm.fillArray(data);
    ArrayStream arrStrm = New!ArrayStream(data);
    auto snd = loadWAV(arrStrm);
    Delete(arrStrm);
    Delete(data);
    istrm.close();
    return snd;
}

/**
 * Simple RIFF/WAV encoder. Encodes WAV to stream
 */
void saveWAV(Sound snd, OutputStream ostrm)
{
    string magic = "RIFF";
    ostrm.writeBytes(magic.ptr, 4);

    int chunkSize = 36 + cast(int)snd.data.length; // total file size - 8
    ostrm.writeLE(chunkSize);

    string format = "WAVE";
    ostrm.writeBytes(format.ptr, 4);

    string fmt = "fmt ";
    ostrm.writeBytes(fmt.ptr, 4);

    int fmtSubchunkSize = 16;
    ostrm.writeLE(fmtSubchunkSize);

    short audioFormat = 1;
    short numChannels = cast(short)snd.channels;
    assert(numChannels == 1 || numChannels == 2);
    int sampleRate = snd.sampleRate; // samples per second
    int byteRate = snd.sampleRate * snd.sampleSize; // bytes per second
    short blockAlign = cast(short)snd.sampleSize; // bytes per sample
    short bitsPerSample;
    if (snd.sampleFormat == SampleFormat.U8)
        bitsPerSample = 8;
    else if (snd.sampleFormat == SampleFormat.S16)
        bitsPerSample = 16;
    else
    {
        assert(0, "Illegal sample format to use with RIFF/WAV");
    }

    ostrm.writeLE(audioFormat);
    ostrm.writeLE(numChannels);
    ostrm.writeLE(sampleRate);
    ostrm.writeLE(byteRate);
    ostrm.writeLE(blockAlign);
    ostrm.writeLE(bitsPerSample);

    string dataID = "data";
    ostrm.writeBytes(dataID.ptr, 4);

    int dataSubchunkSize = cast(int)snd.data.length;
    ostrm.writeLE(dataSubchunkSize);
    ostrm.writeArray(snd.data);
}

/**
 * Encodes WAV to file
 */
void saveWAV(Sound snd, string filename)
{
    auto ostrm = openForOutput(filename);
    saveWAV(snd, ostrm);
    ostrm.close();
}


================================================
FILE: dlib/audio/package.d
================================================
/*
Copyright (c) 2016-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * This package provides basic tools for sound processing. It currently supports 
 * bit depths 8 and 16 (signed and unsigned), as well as arbitrary sample rate and 
 * number of channels. Design principles of dlib.audio are closely akin to dlib.image.
 *
 * Copyright: Timur Gafarov 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio;

public
{
    import dlib.audio.sample;
    import dlib.audio.sound;
    import dlib.audio.synth;
    import dlib.audio.unmanaged;
    import dlib.audio.io;
    import dlib.audio.io.wav;
}


================================================
FILE: dlib/audio/sample.d
================================================
/*
Copyright (c) 2016-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Sample types and conversion utilities
 *
 * Copyright: Timur Gafarov 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.sample;

/**
 * dlib.audio defines four integer sample formats: signed 8-bit, signed 16-bit,
 * unsigned 8-bit, unsigned 16-bit.
 * They are for storage only. All sound processing and sample I/O
 * should be done in floating point numbers. Floating point sample is signed and
 * ranges from -1.0f to 1.0f.
 */
enum SampleFormat
{
    /// signed 8-bit
    S8,
    /// signed 16-bit
    S16,
    /// unsigned 8-bit
    U8,
    /// unsigned 16-bit
    U16
}

/**
 * Convert integer sample to floating point sample
 */
float toFloatSample(ubyte* ptr, SampleFormat format)
{
    float res;
    switch (format)
    {
        case SampleFormat.S8:
            res = *cast(byte*)ptr;
            res /= byte.max;
            break;
        case SampleFormat.S16:
            res = *cast(short*)ptr;
            res /= short.max;
            break;
        case SampleFormat.U8:
            res = *ptr;
            res /= ubyte.max;
            res = res * 2.0f - 1.0f; // normalize to range -1..1
            break;
        case SampleFormat.U16:
            res = *cast(ushort*)ptr;
            res /= ushort.max;
            res = res * 2.0f - 1.0f; // normalize to range -1..1
            break;
        default:
            break;
    }
    return res;
}

/**
 * Convert floating point sample to integer sample
 */
void fromFloatSample(ubyte* ptr, SampleFormat format, float s)
{
    switch (format)
    {
        case SampleFormat.S8:
            *cast(byte*)ptr = cast(byte)(s * byte.max);
            break;
        case SampleFormat.S16:
            *cast(short*)ptr = cast(short)(s * short.max);
            break;
        case SampleFormat.U8:
            *cast(ubyte*)ptr = cast(ubyte)((s + 1.0f) * 0.5f * ubyte.max);
            break;
        case SampleFormat.U16:
            *cast(ushort*)ptr = cast(ushort)((s + 1.0f) * 0.5f * ushort.max);
            break;
        default:
            break;
    }
}


================================================
FILE: dlib/audio/sound.d
================================================
/*
Copyright (c) 2016-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Generic sound interfaces and their implementations
 *
 * Copyright: Timur Gafarov 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.sound;

import std.math;
import dlib.audio.sample;

/**
 * Generalized sound stream class.
 * This can be used to implement any type of sound,
 * including compressed audio streams.
 */
abstract class StreamedSound
{
    /// Number of channels per sample
    @property uint channels();

    /// Number of samples per second, in Hz
    @property uint sampleRate();

    /// Number of bits in each sample channel
    @property uint bitDepth();

    /// Number of bytes in each sample (bitDepth / 8 * channels)
    @property uint sampleSize()
    {
        return (bitDepth / 8) * channels;
    }

    /// Sample format
    @property SampleFormat sampleFormat();

    /// Fill in the buffer with next portion of sound data.
    /// Function returns actual number of bytes written.
    /// At the end of a stream, zero is returned.
    ulong stream(ubyte[] buffer);

    /// Return to the start of a stream
    void reset();
}

/**
 * Sound that can be seeked
 */
abstract class SeekableSound: StreamedSound
{
    /// Number of samples
    @property ulong size();

    /// Duration, in seconds
    @property double duration();

    float opIndex(uint chan, ulong pos);
    float opIndexAssign(float sample, uint chan, ulong pos);
}

/**
 * Sound that is fully kept in memory
 */
abstract class Sound: SeekableSound
{
    /// Raw byte data
    @property ref ubyte[] data();

    /// Make exact copy of the sound
    @property Sound dup();

    /// Make empty sound of the same format
    Sound createSameFormat(uint ch, double dur);
}

/**
 * Generic Sound implementation
 */
class GenericSound: Sound
{
    protected:
    ubyte[] _data;
    ulong _size;
    double _duration;
    uint _channels;
    uint _sampleRate;
    uint _bitDepth;
    SampleFormat _format;

    public:
    this(Sound ras)
    {
        auto rasData = ras.data;
        allocateData(rasData.length);
        for(size_t i = 0; i < _data.length; i++)
            _data[i] = rasData[i];
        _size = ras.size;
        _duration = ras.duration;
        _channels = ras.channels;
        _sampleRate = ras.sampleRate;
        _bitDepth = ras.bitDepth;
        _format = ras.sampleFormat;
    }

    this(double dur,
         uint freq,
         uint numChannels,
         SampleFormat f)
    {
        _duration = dur;
        _sampleRate = freq;
        _channels = numChannels;
        _size = cast(ulong)ceil(dur * freq);
        _format = f;
        if (f == SampleFormat.U8 || f == SampleFormat.S8)
            _bitDepth = 8;
        else if (f == SampleFormat.U16 || f == SampleFormat.S16)
            _bitDepth = 16;
        size_t dataSize = cast(size_t)(_size * (numChannels * (_bitDepth / 8)));
        allocateData(dataSize);
    }

    this(size_t dataSize,
         ulong numSamples,
         double dur,
         uint numChannels,
         uint freq,
         uint bitdepth,
         SampleFormat f)
    {
        allocateData(dataSize);
        _size = numSamples;
        _duration = dur;
        _channels = numChannels;
        _sampleRate = freq;
        _bitDepth = bitdepth;
        _format = f;
    }

    override @property ulong size()
    {
        return _size;
    }

    override @property double duration()
    {
        return _duration;
    }

    override @property uint channels()
    {
        return _channels;
    }

    override @property uint sampleRate()
    {
        return _sampleRate;
    }

    override @property uint bitDepth()
    {
        return _bitDepth;
    }

    override @property SampleFormat sampleFormat()
    {
        return _format;
    }

    override @property ref ubyte[] data()
    {
        return _data;
    }

    protected:
    size_t position; // sample position

    protected void allocateData(size_t size)
    {
        _data = new ubyte[size];
    }

    public:
    override ulong stream(ubyte[] buffer)
    {
        size_t ssize = sampleSize();
        size_t bytePos = position * ssize;
        size_t sizeInBytes = cast(size_t)_size * ssize;

        size_t bytesWritten = buffer.length;
        if (bytePos + buffer.length >= sizeInBytes)
            bytesWritten = sizeInBytes - bytePos;

        for(size_t i = bytePos; i < bytePos + bytesWritten; i++)
        {
            buffer[i] = _data[i];
        }

        return bytesWritten;
    }

    override void reset()
    {
        position = 0;
    }

    override float opIndex(uint chan, ulong pos)
    {
        size_t ssize = sampleSize();
        uint sampleChannelSize = _bitDepth / 8;
        ubyte* samplePtr = &_data[cast(size_t)pos * ssize] + chan * sampleChannelSize;
        return toFloatSample(samplePtr, _format);
    }

    override float opIndexAssign(float s, uint chan, ulong pos)
    {
        size_t ssize = sampleSize();
        uint sampleChannelSize = _bitDepth / 8;
        ubyte* samplePtr = &_data[cast(size_t)pos * ssize] + chan * sampleChannelSize;
        fromFloatSample(samplePtr, _format, s);
        return s;
    }

    override @property Sound dup()
    {
        return new GenericSound(this);
    }

    override Sound createSameFormat(uint ch, double dur)
    {
        return new GenericSound(dur, _sampleRate, ch, _format);
    }
}

/**
 * GenericSound object factory
 */
interface GenericSoundFactory
{
    GenericSound createSound(
        size_t dataSize,
        ulong numSamples,
        double dur,
        uint numChannels,
        uint freq,
        uint bitdepth,
        SampleFormat f);
}

/**
 * GenericSoundFactory implementation for Sound class
 */
class DefaultGenericSoundFactory: GenericSoundFactory
{
    GenericSound createSound(
        size_t dataSize,
        ulong numSamples,
        double dur,
        uint numChannels,
        uint freq,
        uint bitdepth,
        SampleFormat f)
    {
        return new GenericSound(
            dataSize,
            numSamples,
            dur,
            numChannels,
            freq,
            bitdepth,
            f
        );
    }
}

private __gshared DefaultGenericSoundFactory _defaultGenericSoundFactory;

/**
 * GenericSoundFactory singleton
 */
DefaultGenericSoundFactory defaultGenericSoundFactory()
{
    if (!_defaultGenericSoundFactory)
        _defaultGenericSoundFactory = new DefaultGenericSoundFactory();
    return _defaultGenericSoundFactory;
}


================================================
FILE: dlib/audio/synth.d
================================================
/*
Copyright (c) 2016-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Simplest waveform synthesizers
 *
 * Copyright: Timur Gafarov 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.synth;

import std.math;
import std.random;
import dlib.audio.sound;

/**
 * An interface for a synthesizer that maps sample position to -1..1 sample value
 */
interface Synth
{
    /**
     * Evaluate a sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency);
}

/**
 * Sine wave synthesizer
 */
class SineWaveSynth: Synth
{
    /**
     * Evaluate a sine wave sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency)
    {
        double samplePeriod = 1.0 / cast(double)sound.sampleRate;
        double time = position * samplePeriod;
        return sin(2.0 * PI * frequency * time);
    }
}

/**
 * Square wave synthesizer
 */
class SquareWaveSynth: Synth
{
    /**
     * Evaluate square wave sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency)
    {
        double samplePeriod = 1.0 / cast(double)sound.sampleRate;
        double phase = position * samplePeriod * frequency;
        double s = 2.0 * floor(phase) - floor(2.0 * phase) + 1.0;
        return s * 2.0 - 1.0;
    }
}

/**
 * Sawtooth wave synthesizer
 */
class SawtoothWaveSynth: Synth
{
    /**
     * Evaluate sawtooth wave sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency)
    {
        double samplePeriod = 1.0 / cast(double)sound.sampleRate;
        double phase = position * samplePeriod * frequency;
        double s = phase - floor(phase);
        return s * 2.0 - 1.0;
    }
}

/**
 * Triangle wave synthesizer
 */
class TriangleWaveSynth: Synth
{
    /**
     * Evaluate triangle wave sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency)
    {
        double samplePeriod = 1.0 / cast(double)sound.sampleRate;
        double phase = position * samplePeriod * frequency;
        double s = abs(1.0 - fmod(phase, 2.0));
        return s * 2.0 - 1.0;
    }
}

/**
 * Frequency modulation synthesizer
 */
class FMSynth: Synth
{
    Synth carrier;
    Synth modulator;
    float frequencyRatio;

    /**
     * Constructor.
     * 
     * Params:
     *   carrier = carrier waveform
     *   modulator = modulator waveform
     *   frequencyRatio = frequency multiplier for modulator
     */
    this(Synth carrier, Synth modulator, float frequencyRatio)
    {
        this.carrier = carrier;
        this.modulator = modulator;
        this.frequencyRatio = frequencyRatio;
    }

    /**
     * Evaluate FM sample.
     * 
     * Params:
     *   sound = a sound object which parameters are used to discretize a sample
     *   position = sample index
     *   frequency = signal frequency in Hz
     */
    float eval(Sound sound, ulong position, float frequency)
    {
        float m = modulator.eval(sound, position, frequency * frequencyRatio);
        return carrier.eval(sound, position, frequency + m);
    }
}

/**
 * Fill a given portion of a sound with a signal from specified synthesizer.
 * Params:
 *   sound = a sound object to write to
 *   channel = channel to fill (beginning from 0)
 *   synth = synthesizer object
 *   freq = synthesizer frequency
 *   startTime = start time of a signal in seconds
 *   duration = duration of a signal in seconds
 *   amplitude = volume coefficient of a signal
 */
void fillSynth(Sound sound, uint channel, Synth synth, float freq, double startTime, double duration, float amplitude)
{
    ulong startSample = cast(ulong)(startTime * sound.sampleRate);
    ulong endSample = startSample + cast(ulong)(duration * sound.sampleRate);
    if (endSample >= sound.size)
        endSample = sound.size - 1;

    foreach(i; startSample..endSample)
    {
        sound[channel, i] = synth.eval(sound, i - startSample, freq) * amplitude;
    }
}

/**
 * Additively mix a signal from specified synthesizer to a given portion of a sound.
 *   sound = a sound object to write to
 *   channel = channel to fill (beginning from 0)
 *   synth = synthesizer object
 *   freq = synthesizer frequency
 *   startTime = start time of a signal in seconds
 *   duration = duration of a signal in seconds
 *   amplitude = volume coefficient of a signal
 */
void mixSynth(Sound sound, uint channel, Synth synth, float freq, double startTime, double duration, float amplitude)
{
    ulong startSample = cast(ulong)(startTime * sound.sampleRate);
    ulong endSample = startSample + cast(ulong)(duration * sound.sampleRate);
    if (endSample >= sound.size)
        endSample = sound.size - 1;

    foreach(i; startSample..endSample)
    {
        float src = sound[channel, i];
        sound[channel, i] = src + synth.eval(sound, i - startSample, freq) * amplitude;
    }
}

/**
 * Generate random audio signal.
 *   snd = sound
 *   ch = channel to fill (beginning from 0)
 */
void whiteNoise(Sound snd, uint ch)
{
    foreach(i; 0..snd.size)
    {
        snd[ch, i] = uniform(-1.0f, 1.0f);
    }
}

/**
 * Fill the sound with simple sine wave tone.
 *   snd = sound
 *   ch = channel to fill (beginning from 0)
 *   freq = frequency in Hz. For example, a dial tone in Europe is usually 425 Hz
 */
void sineWave(Sound snd, uint ch, float freq)
{
    float samplePeriod = 1.0f / cast(float)snd.sampleRate;
    foreach(i; 0..snd.size)
    {
        snd[ch, i] = sin(samplePeriod * i * freq * 2.0f * PI);
    }
}


================================================
FILE: dlib/audio/unmanaged.d
================================================
/*
Copyright (c) 2016-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * GC-free sound class
 *
 * Copyright: Timur Gafarov 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.audio.unmanaged;

import dlib.core.memory;
import dlib.audio.sample;
import dlib.audio.sound;

/**
 * An implementation of GenericSound that doesn't use garbage collector
 */
class UnmanagedGenericSound: GenericSound
{
    this(Sound ras)
    {
        super(ras);
    }

    this(double dur,
         uint freq,
         uint numChannels,
         SampleFormat f)
    {
        super(dur, freq, numChannels, f);
    }

    this(size_t dataSize,
         ulong numSamples,
         double dur,
         uint numChannels,
         uint freq,
         uint bitdepth,
         SampleFormat f)
    {
        super(dataSize, numSamples, dur, numChannels, freq, bitdepth, f);
    }

    protected override void allocateData(size_t size)
    {
        _data = New!(ubyte[])(size);
    }

    override @property Sound dup()
    {
        return New!UnmanagedGenericSound(this);
    }

    override Sound createSameFormat(uint ch, double dur)
    {
        return New!UnmanagedGenericSound(dur, _sampleRate, ch, _format);
    }

    ~this()
    {
        if (_data)
            Delete(_data);
    }
}

/**
 * GenericSoundFactory implementation for UnmanagedGenericSound class
 */
class UnmanagedGenericSoundFactory: GenericSoundFactory
{
    UnmanagedGenericSound createSound(
        size_t dataSize,
        ulong numSamples,
        double dur,
        uint numChannels,
        uint freq,
        uint bitdepth,
        SampleFormat f)
    {
        return New!UnmanagedGenericSound(
            dataSize,
            numSamples,
            dur,
            numChannels,
            freq,
            bitdepth,
            f
        );
    }
}


================================================
FILE: dlib/coding/package.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Data coding and compression algorithms
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.coding;

public
{
    import dlib.coding.zlib;
    import dlib.coding.varint;
}


================================================
FILE: dlib/coding/varint.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Variable-sized integer type
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.coding.varint;

/**
 * Protobuf-style variable-sized integer
 */
struct Varint
{
    ubyte[8] buffer;
    size_t size;

    /// Returns bytes of an integer
    ubyte[] bytes() return
    {
        return buffer[0..size];
    }
}

/**
 * Returns size in bytes necessary to store an integer
 */
size_t getVarintSize(ulong n)
{
    enum ulong N1 = 128;
    enum ulong N2 = 16384;
    enum ulong N3 = 2097152;
    enum ulong N4 = 268435456;
    enum ulong N5 = 34359738368;
    enum ulong N6 = 4398046511104;
    enum ulong N7 = 562949953421312;
    enum ulong N8 = 72057594037927936;

    return (
        n < N1 ? 1
      : n < N2 ? 2
      : n < N3 ? 3
      : n < N4 ? 4
      : n < N5 ? 5
      : n < N6 ? 6
      : n < N7 ? 7
      :          8
    );
}

///
unittest
{
    assert(getVarintSize(4637734) == 4);
}

/**
 * Encode a fixed-size integer to Varint
 */
Varint encodeVarint(ulong n)
{
    Varint res;
    res.size = getVarintSize(n);
    ubyte* ptr = res.buffer.ptr;

    for (uint i = 0; i < res.size; i++)
    {
        if (i == res.size - 1)
            *(ptr++) = n & 0xFF;
        else
            *(ptr++) = cast(ubyte)(n | 0x80);
        n >>= 7;
    }

    return res;
}

///
unittest
{
    Varint v = encodeVarint(4783);
    assert(v.size == 2);
    assert(v.bytes == [175, 37]);
}

/**
 * Decode Varing to fixed-size integer
 */
ulong decodeVarint(Varint vint)
{
    ulong result = 0;
    int bits = 0;
    ubyte* ptr = vint.buffer.ptr;
    ulong ll;

    while (*ptr & 0x80)
    {
        ll = *ptr;
        result += ((ll & 0x7F) << bits);
        ptr++;
        bits += 7;
    }

    ll = *ptr;
    result += ((ll & 0x7F) << bits);

    return result;
}

///
unittest
{
    Varint v = encodeVarint(2345);
    assert(decodeVarint(v) == 2345);
}


================================================
FILE: dlib/coding/zlib.d
================================================
/*
Copyright (c) 2011-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Zlib compression and decompression
 *
 * Copyright: Timur Gafarov 2011-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.coding.zlib;

import etc.c.zlib;
import dlib.core.memory;

/**
 * Zlib encoder that uses provided fixed-length buffer to store results.
 * Doesn't use garbage collector
 */
struct ZlibBufferedEncoder
{
    z_stream zlibStream;
    ubyte[] buffer;
    ubyte[] input;
    bool ended = true;

    /// Constructor
    this(ubyte[] buf, ubyte[] inp)
    {
        buffer = buf;
        input = inp;
        zlibStream.next_out = buffer.ptr;
        zlibStream.avail_out = cast(uint)buffer.length;
        zlibStream.data_type = Z_BINARY;
        zlibStream.zalloc = null;
        zlibStream.zfree = null;
        zlibStream.opaque = null;

        zlibStream.next_in = inp.ptr;
        zlibStream.avail_in = cast(uint)inp.length;

        deflateInit(&zlibStream, Z_BEST_COMPRESSION);
        ended = false;
    }

    /// Encodes the next portion of data and returns a number of bytes written
    size_t encode()
    {
        zlibStream.next_out = buffer.ptr;
        zlibStream.avail_out = cast(uint)buffer.length;
        zlibStream.total_out = 0;

        while (zlibStream.avail_out > 0)
        {
            int msg = deflate(&zlibStream, Z_FINISH);

            if (msg == Z_STREAM_END)
            {
                deflateEnd(&zlibStream);
                ended = true;
                return zlibStream.total_out;
            }
            else if (msg != Z_OK)
            {
                deflateEnd(&zlibStream);
                return 0;
            }
        }

        return zlibStream.total_out;
    }
}

/**
 * Zlib decoder that uses provided buffer to store results
 * Doesn't use garbage collector
 */
struct ZlibDecoder
{
    z_stream zlibStream;
    ubyte[] buffer;
    int msg = 0;

    bool isInitialized = false;
    bool hasEnded = false;

    /// Constructor
    this(ubyte[] buf)
    {
        buffer = buf;
        zlibStream.next_out = buffer.ptr;
        zlibStream.avail_out = cast(uint)buffer.length;
        zlibStream.data_type = Z_BINARY;
    }

    /**
     * Decodes a stream. Returns true on success, false on error. 
     * Decoded data is stored in buffer field, the buffer is resized if necessary
     */
    bool decode(ubyte[] input)
    {
        zlibStream.next_in = input.ptr;
        zlibStream.avail_in = cast(uint)input.length;

        if (!isInitialized)
        {
            isInitialized = true;
            msg = inflateInit(&zlibStream);
            if (msg)
            {
                inflateEnd(&zlibStream);
                return false;
            }
        }

        while (zlibStream.avail_in)
        {
            msg = inflate(&zlibStream, Z_NO_FLUSH);
            if (msg == Z_STREAM_END)
            {
                inflateEnd(&zlibStream);
                hasEnded = true;
                reallocateBuffer(zlibStream.total_out);
                return true;
            }
            else if (msg != Z_OK)
            {
                inflateEnd(&zlibStream);
                return false;
            }
            else if (zlibStream.avail_out == 0)
            {
                reallocateBuffer(buffer.length * 2);
                zlibStream.next_out = &buffer[buffer.length / 2];
                zlibStream.avail_out = cast(uint)(buffer.length / 2);
            }
        }

        return true;
    }

    void reallocateBuffer(size_t len)
    {
        ubyte[] buffer2 = New!(ubyte[])(len);
        for(uint i = 0; i < buffer2.length; i++)
            if (i < buffer.length)
                buffer2[i] = buffer[i];
        Delete(buffer);
        buffer = buffer2;
    }

    /// Call this when you don't need decoded buffer anymore
    void free()
    {
        Delete(buffer);
    }
}


================================================
FILE: dlib/concurrency/package.d
================================================
/*
Copyright (c) 2019-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * A thread pool for running tasks in parallel
 *
 * Copyright: Timur Gafarov 2019-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.concurrency;

public 
{
    import dlib.concurrency.threadpool;
    import dlib.concurrency.workerthread;
    import dlib.concurrency.taskqueue;
}

================================================
FILE: dlib/concurrency/taskqueue.d
================================================
/*
Copyright (c) 2019-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Copyright: Timur Gafarov 2019-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.concurrency.taskqueue;

import dlib.core.mutex;
import dlib.container.array;
import dlib.concurrency.workerthread;

/**
 * State of a Task
 */
enum TaskState
{
    Valid = 0,
    Invalid = 1
}

/**
 * Task object that encapsulates a delegate
 */
struct Task
{
    TaskState state = TaskState.Invalid;
    void delegate() func;

    void run()
    {
        if (func !is null)
        {
            func();
        }
    }
}

/**
 * Asynchronous task queue
 */
class TaskQueue
{
    protected:
    enum size_t MaxTasks = 64;
    Array!(Task, MaxTasks) tasks;
    Mutex mutex;

    public:
    
    /// Constructor
    this()
    {
        mutex.init();
    }

    ~this()
    {
        tasks.free();
        mutex.destroy();
    }

    /// Number of queued tasks
    size_t count()
    {
        return tasks.length;
    }

    /// Add a task to queue
    bool enqueue(Task task)
    {
        if (tasks.length < MaxTasks)
        {
            mutex.lock();
            tasks.insertFront(task);
            mutex.unlock();
            return true;
        }
        else
            return false;
    }

    /// Remove a task from queue
    Task dequeue()
    {
        if (tasks.length)
        {
            mutex.lock();
            Task t = tasks[tasks.length-1];
            tasks.removeBack(1);
            mutex.unlock();
            return t;
        }
        else
            return Task(TaskState.Invalid, null);
    }
}


================================================
FILE: dlib/concurrency/threadpool.d
================================================
/*
Copyright (c) 2019-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Copyright: Timur Gafarov 2019-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.concurrency.threadpool;

import std.functional;
import dlib.core.memory;
import dlib.core.mutex;
import dlib.concurrency.workerthread;
import dlib.concurrency.taskqueue;

/**
 * An object that manages worker threads and runs tasks on them
 */
class ThreadPool
{
    protected:
    uint maxThreads;
    WorkerThread[] workerThreads;
    TaskQueue taskQueue;
    bool running = true;
    Mutex mutex;

    public:
    
    /// Constructor
    this(uint maxThreads)
    {
        this.maxThreads = maxThreads;
        workerThreads = New!(WorkerThread[])(maxThreads);
        taskQueue = New!TaskQueue();

        mutex.init();

        foreach(i, ref t; workerThreads)
        {
            t = New!WorkerThread(i, this);
            t.start();
        }
    }

    ~this()
    {
        mutex.lock();
        running = false;
        mutex.unlock();

        foreach(i, ref t; workerThreads)
        {
            t.join();
            Delete(t);
        }

        Delete(taskQueue);
        Delete(workerThreads);

        mutex.destroy();
    }

    /// Create a task from delegate
    Task submit(void delegate() taskDele)
    {
        Task task = Task(TaskState.Valid, taskDele);
        if (!taskQueue.enqueue(task))
        {
            task.run();
        }
        return task;
    }

    /// Create a task from function pointer
    Task submit(void function() taskFunc)
    {
        return submit(toDelegate(taskFunc));
    }

    Task request()
    {
        return taskQueue.dequeue();
    }

    bool isRunning()
    {
        return running;
    }

    /// Returns true if all tasks are finished
    bool tasksDone()
    {
        if (taskQueue.count == 0)
        {
            foreach(i, t; workerThreads)
            {
                if (t.busy)
                    return false;
            }

            return true;
        }
        else
            return false;
    }
}

/*
///
unittest
{
    import std.stdio;

    int x = 0;
    int y = 0;

    void task1()
    {
        while(x < 100)
            x += 1;
    }

    void task2()
    {
        while(y < 100)
            y += 1;
    }

    ThreadPool threadPool = New!ThreadPool(2);

    threadPool.submit(&task1);
    threadPool.submit(&task2);

    while(!threadPool.tasksDone) {}

    if (x != 100) writeln(x);
    if (y != 100) writeln(y);

    assert(x == 100);
    assert(y == 100);

    Delete(threadPool);
}
*/


================================================
FILE: dlib/concurrency/workerthread.d
================================================
/*
Copyright (c) 2019-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Copyright: Timur Gafarov 2019-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.concurrency.workerthread;

import dlib.core.thread;
import dlib.concurrency.threadpool;
import dlib.concurrency.taskqueue;

/**
 * A thread that is created by ThreadPool
 */
class WorkerThread: Thread
{
    size_t id;
    ThreadPool pool;
    protected bool _busy = false;

    /// Constructor
    this(size_t id, ThreadPool pool)
    {
        super(&threadFunc);
        this.id = id;
        this.pool = pool;
    }

    bool busy()
    {
        return _busy;
    }

    protected void threadFunc()
    {
        while(pool.isRunning)
        {
            Task task = pool.request();
            if (task.state != TaskState.Invalid)
            {
                _busy = true;
                task.run();
                _busy = false;
            }
        }
    }
}


================================================
FILE: dlib/container/array.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Dynamic (expandable) array with random access
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Roman Vlasov, Andrey Penechko, Eugene Wissner, Roman Chistokhodov, aferust, ijet
 */
module dlib.container.array;

import std.traits;
import dlib.core.memory;

/**
 * GC-free dynamic array implementation.
 * Very efficient for small-sized arrays.
 */
struct Array(T, size_t chunkSize = 32)
{
  private:
    T[chunkSize] staticStorage;
    T[] dynamicStorage;
    uint numChunks = 0;
    uint pos = 0;

    /**
     * Get pointer to stored data
     */
    private T* storage() nothrow
    {
        if (numChunks == 0)
            return staticStorage.ptr;
        else
            return dynamicStorage.ptr;
    }

    private const(T)* readOnlyStorage() const nothrow
    {
        if (numChunks == 0)
            return staticStorage.ptr;
        else
            return dynamicStorage.ptr;
    }

    private void addChunk()
    {
        if (numChunks == 0)
        {
            dynamicStorage = New!(T[])(chunkSize);
        }
        else
        {
            reallocateArray(
                dynamicStorage,
                dynamicStorage.length + chunkSize);
        }
        numChunks++;
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        assert(arr.length == 0);
        arr.addChunk();
        assert(arr.length == 0);
    }

  public:
    /**
     * Returns true if the array uses dynamic memory.
     */
    @property bool isDynamic() const
    {
        return dynamicStorage.length > 0;
    }

    /**
     * Preallocate memory without resizing.
     */
    void reserve(const(size_t) amount)
    {
        if (amount > pos && amount > staticStorage.length)
        {
            if (numChunks == 0)
            {
                dynamicStorage = New!(T[])(amount);
                foreach(i, v; staticStorage)
                    dynamicStorage[i] = v;
            }
            else
            {
                reallocateArray(dynamicStorage, amount);
            }

            numChunks = cast(uint)(amount / 32 + amount % 32);
        }
    }

    ///
    unittest
    {
        Array!int arr;
        arr.reserve(100);
        assert(arr.length == 0);
        assert(arr.dynamicStorage.length == 100);
    }

    /**
     * Resize array and initialize newly added elements with initValue.
     */
    void resize(const(size_t) newLen, T initValue)
    {
        if (newLen > pos)
        {
            reserve(newLen);
            for(size_t i = pos; i < newLen; i++)
            {
                storage[i] = initValue;
            }
        }

        pos = cast(uint)newLen;
    }

    ///
    unittest
    {
        Array!int arr;
        arr.resize(100, 1);
        assert(arr.length == 100);
        assert(arr[50] == 1);
    }

    /**
     * Shift contents of array to the right.
     * It inreases the size of array by 1.
     * The first element becomes default initialized.
     */
    void shiftRight()
    {
        insertBack(T.init);

        for(uint i = pos-1; i > 0; i--)
        {
            storage[i] = storage[i-1];
        }
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.shiftRight();
        assert(arr.length == 1);
        assert(arr[0] == int.init);

        arr[0] = 1;
        arr.insertBack([2,3]);

        arr.shiftRight();
        assert(arr.length == 4);
        assert(arr[0] == 1);
        assert(arr[1] == 1);
        assert(arr[2] == 2);
        assert(arr[3] == 3);
    }

    /**
     * Shift contents of array to the left by n positions.
     * Does not change the size of array.
     * n of last elements becomes default initialized.
     */
    void shiftLeft(const(uint) n)
    {
        for(uint i = 0; i < pos; i++)
        {
            if (n + i < pos)
                storage[i] = storage[n + i];
            else
                storage[i] = T.init;
        }
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.shiftLeft(1);
        assert(arr.length == 0);

        arr.insertBack([1,2,3,4,5]);

        arr.shiftLeft(2);
        assert(arr.length == 5);
        assert(arr[0] == 3);
        assert(arr[1] == 4);
        assert(arr[2] == 5);
        assert(arr[3] == int.init);
        assert(arr[4] == int.init);
    }

    /**
     * Append single element c to the end.
     */
    void insertBack(T c)
    {
        if (numChunks == 0)
        {
            staticStorage[pos] = c;
            pos++;
            if (pos == chunkSize)
            {
                addChunk();
                foreach(i, ref v; dynamicStorage)
                    v = staticStorage[i];
            }
        }
        else
        {
            if (pos == dynamicStorage.length)
                addChunk();

            dynamicStorage[pos] = c;
            pos++;
        }
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        foreach(i; 0..16) {
            arr.insertBack(i);
        }
        assert(arr.length == 16);
        arr.insertBack(16);
        assert(arr.length == 17);
        assert(arr[16] == 16);
    }

    /**
     * Append element to the start.
     */
    void insertFront(T c)
    {
        shiftRight();
        storage[0] = c;
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertFront(1);
        arr.insertBack(2);
        arr.insertFront(0);
        assert(arr.data == [0,1,2]);
    }

    /**
     * Append all elements of slice s to the end.
     */
    void insertBack(const(T)[] s)
    {
        foreach(c; s)
            insertBack(cast(T)c);
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1,2,3,4]);
        assert(arr.data == [1,2,3,4]);
        arr.insertBack([5,6,7,8]);
        assert(arr.data == [1,2,3,4,5,6,7,8]);
    }

    /**
     * Append all elements of slice s to the start.
     */
    void insertFront(const(T)[] s)
    {
        foreach_reverse(c; s)
            insertFront(cast(T)c);
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertFront([5,6,7,8]);
        assert(arr.data == [5,6,7,8]);
        arr.insertFront([1,2,3,4]);
        assert(arr.data == [1,2,3,4,5,6,7,8]);
    }

    /**
     * Same as insertBack, but in operator form.
     */
    auto opOpAssign(string op)(T c) if (op == "~")
    {
        insertBack(c);
        return this;
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr ~= 1;
        arr ~= 2;
        assert(arr.data == [1,2]);
    }

    /**
     * Same as insertBack, but in operator form.
     */
    auto opOpAssign(string op)(const(T)[] s) if (op == "~")
    {
        insertBack(s);
        return this;
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr ~= [1,2,3];
        assert(arr.data == [1,2,3]);
    }

    /**
     * Remove n of elements from the end.
     * Returns: number of removed elements.
     */
    uint removeBack(const(uint) n)
    {
        if (pos == n)
        {
            pos = 0;
            return n;
        }
        else if (pos >= n)
        {
            pos -= n;
            return n;
        }
        else
        {
            uint res = pos;
            pos = 0;
            return res;
        }
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1,2,3]);
        assert(arr.removeBack(3) == 3);
        assert(arr.length == 0);

        arr.insertBack([1,2,3,4]);
        assert(arr.removeBack(2) == 2);
        assert(arr.data == [1,2]);

        assert(arr.removeBack(3) == 2);
        assert(arr.length == 0);
    }

    /**
     * Remove n of elements from the start.
     * Returns: number of removed elements.
     */
    uint removeFront(const(uint) n)
    {
        if (pos == n)
        {
            pos = 0;
            return n;
        }
        else if (pos > n)
        {
            shiftLeft(n);
            pos -= n;
            return n;
        }
        else
        {
            uint res = pos;
            pos = 0;
            return res;
        }
    }

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1,2,3]);
        assert(arr.removeFront(3) == 3);

        arr.insertBack([1,2,3,4]);
        assert(arr.removeFront(2) == 2);
        assert(arr.data == [3,4]);

        assert(arr.removeFront(3) == 2);
        assert(arr.length == 0);
    }

    /**
     * Inserts an element by a given index
     * (resizing an array and shifting elements).
     */
    void insertKey(const(size_t) i, T v)
    {
        if (i < pos)
        {
            T* s = storage();

            insertBack(T.init);

            for (size_t p = pos-1; p > i; p--)
            {
                s[p] = s[p-1];
            }

            s[i] = v;
        }
    }

    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1, 4, 5]);

        arr.insertKey(1, 7);
        assert(arr.length == 4);
        assert(arr.data == [1, 7, 4, 5]);
    }

    /**
     * Removes an element by a given index.
     */
    void removeKey(const(size_t) i)
    {
        if (i < pos)
        {
            T* s = storage();
            for (size_t p = i+1; p <= pos; p++)
            {
                s[p-1] = s[p];
            }

            pos--;
        }
    }

    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1, 4, 5]);

        arr.removeKey(1);
        assert(arr.length == 2);
        assert(arr.data == [1, 5]);
    }

    alias insertAt = insertKey;
    alias removeAt = removeKey;

    /**
     * If obj is in array, remove its first occurence and return true.
     * Otherwise do nothing and return false.
     */
    bool removeFirst(T obj)
    {
        size_t index;
        bool found = false;

        for (size_t i = 0; i < data.length; i++)
        {
            T o = data[i];

            static if (isArray!T)
            {
                if (o[] == obj[])
                {
                    index = i;
                    found = true;
                    break;
                }
            }
            else
            {
                if (o is obj)
                {
                    index = i;
                    found = true;
                    break;
                }
            }
        }

        if (found)
        {
            removeKey(index);
            return true;
        }

        return false;
    }

    // For backward compatibility
    alias append = insertBack;
    alias appendLeft = insertFront;
    alias remove = removeBack;
    alias removeLeft = removeFront;

    /**
     * Get number of elements in array.
     */
    size_t length() const nothrow
    {
        return pos;
    }

    alias opDollar = length;

    ///
    unittest
    {
        Array!int arr;
        scope(exit) arr.free();

        arr.insertBack([1,2,3]);
        assert(arr.length == 3);
    }

    /**
     * Get slice of data
     */
    T[] data() nothrow
    {
        return storage[0..pos];
    }

    const(T)[] readOnlyData() const nothrow
    {
        return readOnlyStorage[0..pos];
    }

    ///
    unittest
    {
        Array!(int,4) arr;
        scope(exit) arr.free();

        foreach(i; 0..6) {
            arr.insertBack(i);
        }

        assert(arr.data == [0,1,2,3,4,5]);
    }

    /**
     * Access element by index.
     */
    T opIndex(const(size_t) index)
    {
        return data[index];
    }

    /**
     * Access by slice.
     */
    T[] opSlice(const(size_t) start, const(size_t) end)
    {
        return data[start..end];
    }

    /**
     * Set element t for index.
     */
    T opIndexAssign(T t, const(size_t) index)
    {
        data[index] = t;
        return t;
    }

    /**
     * Iterating over array via foreach.
     */
    int opApply(scope int delegate(size_t i, ref T) dg)
    {
        int result = 0;

        foreach(i, ref v; data)
        {
            result = dg(i, v);
            if (result)
                break;
        }

        return result;
    }

    /**
     * Iterating over array via foreach_reverse.
     */
    int opApplyReverse(scope int delegate(size_t i, ref T) dg)
    {
        int result = 0;

        for(size_t i =  length; i-- > 0; )
        {
            result = dg(i, data[i]);
            if (result)
                break;
        }

        return result;
    }

    ///
    unittest
    {
        Array!(int,4) arr;
        scope(exit) arr.free();

        int[4] values;
        arr.insertBack([1,2,3,4]);
        foreach(i, ref val; arr) {
            values[i] = val;
            if(values[i] == 4) {
                break;
            }
        }
        assert(values[] == arr.data);
    }

    /**
     * Iterating over array via foreach.
     */
    int opApply(scope int delegate(ref T) dg)
    {
        int result = 0;

        foreach(i, ref v; data)
        {
            result = dg(v);
            if (result)
                break;
        }

        return 0;
    }

     /**
     * Iterating over array via foreach_reverse.
     */
    int opApplyReverse(scope int delegate(ref T) dg)
    {
        int result = 0;

        for(size_t i = length; i-- > 0; )
        {
            result = dg(data[i]);
            if (result)
                break;
        }

        return result;
    }

    ///
    unittest
    {
        Array!(int,4) arr;
        scope(exit) arr.free();

        int[] values;
        arr.insertBack([1,2,3,4]);
        foreach(ref val; arr) {
            values ~= val;
        }
        assert(values[] == arr.data);
    }

    /**
     * Free dynamically allocated memory used by array.
     */
    void free()
    {
        if (dynamicStorage.length)
            Delete(dynamicStorage);
        numChunks = 0;
        pos = 0;
    }
}

void reallocateArray(T)(ref T[] buffer, const(size_t) len)
{
    T[] buffer2 = New!(T[])(len);
    for(uint i = 0; i < buffer2.length; i++)
        if (i < buffer.length)
            buffer2[i] = buffer[i];
    Delete(buffer);
    buffer = buffer2;
}

///
unittest
{
    auto arr = New!(int[])(3);
    arr[0] = 1; arr[1] = 2; arr[2] = 3;

    reallocateArray(arr, 2);
    assert(arr.length == 2);
    assert(arr[0] == 1);
    assert(arr[1] == 2);

    reallocateArray(arr, 4);
    assert(arr.length == 4);
    assert(arr[0] == 1);
    assert(arr[1] == 2);
}


================================================
FILE: dlib/container/bst.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Binary search tree
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Andrey Penechko
 */
module dlib.container.bst;

import dlib.core.memory;

/**
 * GC-free binary search tree implementation.
 */
class BST(T)
{
    bool root;
    BST left = null;
    BST right = null;
    int key = 0;

    T value;

    this()
    {
        root = true;
    }

    this(int k, T v)
    {
        key = k;
        value = v;
        root = false;
    }

    ~this()
    {
        clear();
    }

    void insert(int k, T v)
    {
        if (k < key)
        {
            if (left is null) left = allocate!(BST)(k, v);
            else left.insert(k, v);
        }
        else if (k > key)
        {
            if (right is null) right = allocate!(BST)(k, v);
            else right.insert(k, v);
        }
        else value = v;
    }

    BST find(int k)
    {
        if (k < key)
        {
            if (left !is null) return left.find(k);
            else return null;
        }
        else if (k > key)
        {
            if (right !is null) return right.find(k);
            else return null;
        }
        else return this;
    }

    protected BST findLeftMost()
    {
        if (left is null) return this;
        else return left.findLeftMost();
    }

    void remove(int k, BST par = null)
    {
        if (k < key)
        {
            if (left !is null) left.remove(k, this);
            else return;
        }
        else if (k > key)
        {
            if (right !is null) right.remove(k, this);
            else return;
        }
        else
        {
            if (left !is null && right !is null)
            {
                auto m = right.findLeftMost();
                key = m.key;
                value = m.value;
                right.remove(key, this);
            }
            else if (this == par.left)
            {
                par.left = (left !is null)? left : right;
            }
            else if (this == par.right)
            {
                par.right = (left !is null)? left : right;
            }
        }
    }

    void traverse(void function(int, T) func)
    {
        if (left !is null)
            left.traverse(func);
        if (!root)
            func(key, value);
        if (right !is null)
            right.traverse(func);
    }

    int opApply(scope int delegate(int, ref T) dg)
    {
        int result = 0;

        if (left !is null)
        {
            result = left.opApply(dg);
            if (result)
                return result;
        }

        if (!root)
            dg(key, value);

        if (right !is null)
        {
            result = right.opApply(dg);
            if (result)
                return result;
        }

        return result;
    }

    void clear()
    {
        if (left !is null)
        {
            left.clear();
            deallocate(left);
            left = null;
        }
        if (right !is null)
        {
            right.clear();
            deallocate(right);
            right = null;
        }
    }
}


================================================
FILE: dlib/container/buffer.d
================================================
/*
Copyright (c) 2016-2025 Eugene Wissner

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Copyright: Eugene Wissner 2016-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Eugene Wissner
 */
module dlib.container.buffer;

import dlib.memory;

version (unittest)
{
    private int fillBuffer(ubyte[] buffer,
                           in size_t size,
                           int start = 0,
                           int end = 10) @nogc pure nothrow
    in
    {
        assert(start < end);
    }
    do
    {
        auto numberRead = end - start;
        for (ubyte i; i < numberRead; ++i)
        {
            buffer[i] = cast(ubyte) (start + i);
        }
        return numberRead;
    }
}

/**
 * Interface for implemeting input/output buffers.
 */
interface Buffer
{
    /**
     * Returns: The size of the internal buffer.
     */
    @property size_t capacity() const @nogc @safe pure nothrow;

    /**
     * Returns: Data size.
     */
    @property size_t length() const @nogc @safe pure nothrow;

    /**
     * Returns: Available space.
     */
    @property size_t free() const @nogc @safe pure nothrow;

    /**
     * Params:
     *     start = Start position.
     *     end   = End position.
     *
     * Returns: Array between $(D_PARAM start) and $(D_PARAM end).
     */
    @property ubyte[] opSlice(size_t start, size_t end)
    in
    {
        assert(start <= end);
        assert(end <= length);
    }

    /**
    * Returns: Length of available data.
    */
    @property size_t opDollar() const pure nothrow @safe @nogc;

    /**
     * Returns: Data chunk.
     */
    @property ubyte[] opIndex();
}

/**
 * Self-expanding buffer, that can be used with functions returning the number
 * of the read bytes.
 *
 * This buffer supports asynchronous reading. It means you can pass a new chunk
 * to an asynchronous read function during you are working with already
 * available data. But only one asynchronous call at a time is supported. Be
 * sure to call $(D_PSYMBOL ReadBuffer.clear()) before you append the result
 * of the pended asynchronous call.
 */
class ReadBuffer : Buffer
{
    /// Internal buffer.
    protected ubyte[] buffer_;

    /// Filled buffer length.
    protected size_t length_;

    /// Start of available data.
    protected size_t start;

    /// Last position returned with $(D_KEYWORD []).
    protected size_t ring;

    /// Available space.
    protected immutable size_t minAvailable;

    /// Size by which the buffer will grow.
    protected immutable size_t blockSize;

    invariant
    {
        assert(length_ <= buffer_.length);
        assert(blockSize > 0);
        assert(minAvailable > 0);
    }

    /**
     * Creates a new read buffer.
     *
     * Params:
     *     size         = Initial buffer size and the size by which the buffer
     *                    will grow.
     *     minAvailable = minimal size should be always  available to fill.
     *                    So it will reallocate if $(D_INLINECODE
     *                    $(D_PSYMBOL free) < $(D_PARAM minAvailable)
     *                    ).
     */
    this(size_t size = 8192,
         size_t minAvailable = 1024)
    {
        this.minAvailable = minAvailable;
        this.blockSize = size;
        defaultAllocator.resizeArray!ubyte(buffer_, size);
    }

    /**
     * Deallocates the internal buffer.
     */
    ~this()
    {
        defaultAllocator.dispose(buffer_);
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!ReadBuffer;
        assert(b.capacity == 8192);
        assert(b.length == 0);

        defaultAllocator.dispose(b);
    }

    /**
     * Returns: The size of the internal buffer.
     */
    @property size_t capacity() const @nogc @safe pure nothrow
    {
        return buffer_.length;
    }

    /**
     * Returns: Data size.
     */
    @property size_t length() const @nogc @safe pure nothrow
    {
        return length_ - start;
    }

    /**
     * Clears the buffer.
     *
     * Returns: $(D_KEYWORD this).
     */
    ReadBuffer clear() pure nothrow @safe @nogc
    {
        start = length_ = ring;
        return this;
    }

    /**
     * Returns: Available space.
     */
    @property size_t free() const pure nothrow @safe @nogc
    {
        return length > ring ? capacity - length : capacity - ring;
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!ReadBuffer;
        size_t numberRead;

        // Fills the buffer with values 0..10
        assert(b.free == b.blockSize);

        numberRead = fillBuffer(b[], b.free, 0, 10);
        b += numberRead;
        assert(b.free == b.blockSize - numberRead);
        b.clear();
        assert(b.free == b.blockSize);

        defaultAllocator.dispose(b);
    }

    /**
     * Appends some data to the buffer.
     *
     * Params:
     *     length = Number of the bytes read.
     *
     * Returns: $(D_KEYWORD this).
     */
    ReadBuffer opOpAssign(string op)(size_t length)
        if (op == "+")
    {
        length_ += length;
        ring = start;
        return this;
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!ReadBuffer;
        size_t numberRead;
        ubyte[] result;

        // Fills the buffer with values 0..10
        numberRead = fillBuffer(b[], b.free, 0, 10);
        b += numberRead;

        result = b[0..$];
        assert(result[0] == 0);
        assert(result[1] == 1);
        assert(result[9] == 9);
        b.clear();

        // It shouldn't overwrite, but append another 5 bytes to the buffer
        numberRead = fillBuffer(b[], b.free, 0, 10);
        b += numberRead;

        numberRead = fillBuffer(b[], b.free, 20, 25);
        b += numberRead;

        result = b[0..$];
        assert(result[0] == 0);
        assert(result[1] == 1);
        assert(result[9] == 9);
        assert(result[10] == 20);
        assert(result[14] == 24);

        defaultAllocator.dispose(b);
    }

    /**
     * Returns: Length of available data.
     */
    @property size_t opDollar() const pure nothrow @safe @nogc
    {
        return length;
    }

    /**
     * Params:
     *     start = Start position.
     *     end   = End position.
     *
     * Returns: Array between $(D_PARAM start) and $(D_PARAM end).
     */
    @property ubyte[] opSlice(size_t start, size_t end) pure nothrow @safe @nogc
    {
        return buffer_[this.start + start .. this.start + end];
    }

    /**
     * Returns a free chunk of the buffer.
     *
     * Add ($(D_KEYWORD +=)) the number of the read bytes after using it.
     *
     * Returns: A free chunk of the buffer.
     */
    ubyte[] opIndex()
    {
        if (start > 0)
        {
            auto ret = buffer_[0..start];
            ring = 0;
            return ret;
        }
        else
        {
            if (capacity - length < minAvailable)
            {
                defaultAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
            }
            ring = length_;
            return buffer_[length_..$];
        }
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!ReadBuffer;
        size_t numberRead;
        ubyte[] result;

        // Fills the buffer with values 0..10
        numberRead = fillBuffer(b[], b.free, 0, 10);
        b += numberRead;

        assert(b.length == 10);
        result = b[0..$];
        assert(result[0] == 0);
        assert(result[9] == 9);
        b.clear();
        assert(b.length == 0);

        defaultAllocator.dispose(b);
    }
}

/**
 * Circular, self-expanding buffer with overflow support. Can be used with
 * functions returning returning the number of the transferred bytes.
 *
 * The buffer is optimized for situations where you read all the data from it
 * at once (without writing to it occasionally). It can become ineffective if
 * you permanently keep some data in the buffer and alternate writing and
 * reading, because it may allocate and move elements.
 */
class WriteBuffer : Buffer
{
    /// Internal buffer.
    protected ubyte[] buffer_;

    /// Buffer start position.
    protected size_t start;

    /// Buffer ring area size. After this position begins buffer overflow area.
    protected size_t ring;

    /// Size by which the buffer will grow.
    protected immutable size_t blockSize;

    /// The position of the free area in the buffer.
    protected size_t position;

    invariant
    {
        assert(blockSize > 0);
        // position can refer to an element outside the buffer if the buffer is full.
        assert(position <= buffer_.length);
    }

    /**
     * Params:
     *  size = Initial buffer size and the size by which the buffer
     *            will grow.
     */
    this(size_t size = 8192)
    {
        blockSize = size;
        ring = size - 1;
        defaultAllocator.resizeArray!ubyte(buffer_, size);
    }

    /**
     * Deallocates the internal buffer.
     */
    ~this()
    {
        defaultAllocator.dispose(buffer_);
    }

    /**
     * Returns: The size of the internal buffer.
     */
    @property size_t capacity() const @nogc @safe pure nothrow
    {
        return buffer_.length;
    }

    /**
     * Note that $(D_PSYMBOL length) doesn't return the real length of the data,
     * but only the array length that will be returned with $(D_PSYMBOL buffer)
     * next time. Be sure to call $(D_PSYMBOL buffer) and set $(D_KEYWORD +=)
     * until $(D_PSYMBOL length) returns 0.
     *
     * Returns: Data size.
     */
    @property size_t length() const @nogc @safe pure nothrow
    {
        if (position > ring || position < start) // Buffer overflowed
        {
            return ring - start + 1;
        }
        else
        {
            return position - start;
        }
    }

    /**
    * Returns: Length of available data.
    */
    @property size_t opDollar() const pure nothrow @safe @nogc
    {
        return length;
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!WriteBuffer(4);
        ubyte[3] buf = [48, 23, 255];

        b ~= buf;
        assert(b.length == 3);
        b += 2;
        assert(b.length == 1);

        b ~= buf;
        assert(b.length == 2);
        b += 2;
        assert(b.length == 2);

        b ~= buf;
        assert(b.length == 5);
        b += b.length;
        assert(b.length == 0);

        defaultAllocator.dispose(b);
    }

    /**
     * Returns: Available space.
     */
    @property size_t free() const @nogc @safe pure nothrow
    {
        return capacity - length;
    }

    /**
     * Appends data to the buffer.
     *
     * Params:
     *     buffer = Buffer chunk got with $(D_PSYMBOL buffer).
     */
    WriteBuffer opOpAssign(string op)(ubyte[] buffer)
        if (op == "~")
    {
        size_t end, start;

        if (position >= this.start && position <= ring)
        {
            auto afterRing = ring + 1;

            end = position + buffer.length;
            if (end > afterRing)
            {
                end = afterRing;
            }
            start = end - position;
            buffer_[position..end] = buffer[0..start];
            if (end == afterRing)
            {
                position = this.start == 0 ? afterRing : 0;
            }
            else
            {
                position = end;
            }
        }

        // Check if we have some free space at the beginning
        if (start < buffer.length && position < this.start)
        {
            end = position + buffer.length - start;
            if (end > this.start)
            {
                end = this.start;
            }
            auto areaEnd = end - position + start;
            buffer_[position..end] = buffer[start..areaEnd];
            position = end == this.start ? ring + 1 : end - position;
            start = areaEnd;
        }

        // And if we still haven't found any place, save the rest in the overflow area
        if (start < buffer.length)
        {
            end = position + buffer.length - start;
            if (end > capacity)
            {
                auto newSize = end / blockSize * blockSize + blockSize;

                defaultAllocator.resizeArray!ubyte(buffer_, newSize);
            }
            buffer_[position..end] = buffer[start..$];
            position = end;
            if (this.start == 0)
            {
                ring = capacity - 1;
            }
        }

        return this;
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!WriteBuffer(4);
        ubyte[3] buf = [48, 23, 255];

        b ~= buf;
        assert(b.capacity == 4);
        assert(b.buffer_[0] == 48 && b.buffer_[1] == 23 && b.buffer_[2] == 255);

        b += 2;
        b ~= buf;
        assert(b.capacity == 4);
        assert(b.buffer_[0] == 23 && b.buffer_[1] == 255
            && b.buffer_[2] == 255 && b.buffer_[3] == 48);

        b += 2;
        b ~= buf;
        assert(b.capacity == 8);
        assert(b.buffer_[0] == 23 && b.buffer_[1] == 255
            && b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255);

        defaultAllocator.dispose(b);

        b = make!WriteBuffer(defaultAllocator, 2);

        b ~= buf;
        assert(b.start == 0);
        assert(b.capacity == 4);
        assert(b.ring == 3);
        assert(b.position == 3);

        defaultAllocator.dispose(b);
    }

    /**
     * Sets how many bytes were written. It will shrink the buffer
     * appropriately. Always set this property after calling
     * $(D_PSYMBOL buffer).
     *
     * Params:
     *     length = Length of the written data.
     *
     * Returns: $(D_KEYWORD this).
     */
    @property WriteBuffer opOpAssign(string op)(size_t length) pure nothrow @safe @nogc
        if (op == "+")
    in
    {
        assert(length <= this.length);
    }
    do
    {
        auto afterRing = ring + 1;
        auto oldStart = start;

        if (length <= 0)
        {
            return this;
        }
        else if (position <= afterRing)
        {
            start += length;
            if (start > 0 && position == afterRing)
            {
                position = oldStart;
            }
        }
        else
        {
            auto overflow = position - afterRing;

            if (overflow > length) {
                buffer_[start.. start + length] = buffer_[afterRing.. afterRing + length];
                buffer_[afterRing.. afterRing + length] = buffer_[afterRing + length ..position];
                position -= length;
            }
            else if (overflow == length)
            {
                buffer_[start.. start + overflow] = buffer_[afterRing..position];
                position -= overflow;
            }
            else
            {
                buffer_[start.. start + overflow] = buffer_[afterRing..position];
                position = overflow;
            }
            start += length;

            if (start == position)
            {
                if (position != afterRing)
                {
                    position = 0;
                }
                start = 0;
                ring = capacity - 1;
            }
        }
        if (start > ring)
        {
            start = 0;
        }
        return this;
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!WriteBuffer;
        ubyte[6] buf = [23, 23, 255, 128, 127, 9];

        b ~= buf;
        assert(b.length == 6);
        b += 2;
        assert(b.length == 4);
        b += 4;
        assert(b.length == 0);

        defaultAllocator.dispose(b);
    }

    /**
     * Returns a chunk with data.
     *
     * After calling it, set $(D_KEYWORD +=) to the length could be
     * written.
     *
     * $(D_PSYMBOL buffer) may return only part of the data. You may need
     * to call it (and set $(D_KEYWORD +=) several times until
     * $(D_PSYMBOL length) is 0). If all the data can be written,
     * maximally 3 calls are required.
     *
     * Returns: A chunk of data buffer.
     */
    @property ubyte[] opSlice(size_t start, size_t end) pure nothrow @safe @nogc
    {
        immutable internStart = this.start + start;

        if (position > ring || position < start) // Buffer overflowed
        {
            return buffer_[this.start.. ring + 1 - length + end];
        }
        else
        {
            return buffer_[this.start.. this.start + end];
        }
    }

    ///
    unittest
    {
        auto b = defaultAllocator.make!WriteBuffer(6);
        ubyte[6] buf = [23, 23, 255, 128, 127, 9];

        b ~= buf;
        assert(b[0..$] == buf[0..6]);
        b += 2;

        assert(b[0..$] == buf[2..6]);

        b ~= buf;
        assert(b[0..$] == buf[2..6]);
        b += b.length;

        assert(b[0..$] == buf[0..6]);
        b += b.length;

        defaultAllocator.dispose(b);
    }

    /**
     * After calling it, set $(D_KEYWORD +=) to the length could be
     * written.
     *
     * $(D_PSYMBOL buffer) may return only part of the data. You may need
     * to call it (and set $(D_KEYWORD +=) several times until
     * $(D_PSYMBOL length) is 0). If all the data can be written,
     * maximally 3 calls are required.
     *
     * Returns: A chunk of data buffer.
     */
    @property ubyte[] opIndex() pure nothrow @safe @nogc
    {
        return opSlice(0, length);
    }
}


================================================
FILE: dlib/container/dict.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Trie-based dictionary (associative array) that can use any type as a key
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Andrey Penechko, Roman Chistokhodov, ijet
 */
module dlib.container.dict;

import std.stdio;
import std.traits;
import std.format;
import std.string;
import dlib.core.memory;
import dlib.container.array;

size_t dataSize(T)(T v)
{
    static if (is(T == class) || is(T == interface))
        return (void*).sizeof;
    else
    static if (isArray!T)
        return v.length * (ForeachType!T).sizeof;
    else
        return T.sizeof;
}

auto byteRange(T)(T v)
{
    struct R
    {
        T value;
        size_t size;
        size_t offset;

        this(T v)
        {
            value = v;
            size = dataSize(v);
            offset = 0;
        }

        @property bool empty()
        {
            return (offset >= size);
        }

        @property ubyte front()
        {
            ubyte* ptr;
            static if (isArray!T) { ptr = (cast(ubyte[])value).ptr;}
            else { ptr = cast(ubyte*)&value; }
            return ptr[offset];
        }

        void popFront()
        {
            offset++;
        }
    }

    return R(v);
}

/**
 * Trie-based dictionary (associative array) that can use any type as a key. No hash functions are required.
 */
class Trie(T, K)
{
    T value;
    K key;
    ubyte symbol;
    Array!(Trie!(T, K)) children;
    bool active = false;
    size_t length = 0;

    this()
    {
    }

    this(ubyte s)
    {
        symbol = s;
    }

    /// Set value by key.
    void set(K k, T v)
    {
        Trie!(T, K) current = this;
        foreach(s; byteRange(k))
        {
            bool found = false;
            foreach(c; current.children)
            {
                if (c.symbol == s)
                {
                    current = c;
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                auto n = New!(Trie!(T, K))(s);
                current.children.append(n);
                current = n;
            }
        }

        if (current !is this)
        {
            current.value = v;
            current.key = k;

            if (!current.active)
            {
                current.active = true;
                length++;
            }
        }
    }

    /// Get value by key. Returns null if the element does not exist in trie.
    T* get(K k)
    {
        Trie!(T, K) current = this;
        foreach(ubyte s; byteRange(k))
        {
            bool found = false;
            foreach(c; current.children)
            {
                if (c.symbol == s)
                {
                    found = true;
                    current = c;
                    break;
                }
            }

            if (!found)
                return null;
        }

        if (current !is this)
        {
            if (current.active &&
                current.key == k)
            {
                return &current.value;
            }
        }

        return null;
    }

    /// Remove element by key.
    void remove(K k)
    {
        Trie!(T, K) current = this;
        foreach(ubyte s; byteRange(k))
        {
            bool found = false;
            foreach(c; current.children)
            {
                if (c.symbol == s)
                {
                    found = true;
                    current = c;
                    break;
                }
            }

            if (!found)
                return;
        }

        if (current !is this)
        {
            if (current.active &&
                current.key == k)
            {
                current.active = false;
                length--;
            }
        }
    }

    /// Get value by key. It's an error to access non-existing key.
    T opIndex(K k)
    {
        T* v = get(k);
        if (v !is null)
            return *v;
        else
            assert(0, format("Non-existing key in Trie.opIndex: %s", k));
    }

    /// Set value by key
    T opIndexAssign(T v, K k)
    {
        set(k, v);
        return v;
    }

    ///
    T* opBinaryRight(string op)(K k) if (op == "in")
    {
        return get(k);
    }

    int opApply(scope int delegate(K, ref T) dg)
    {
        int result = 0;

        foreach(c; children)
        {
            if (c.active)
                result = dg(c.key, c.value);

            if (result)
                break;

            result = c.opApply(dg);

            if (result)
                break;
        }

        return result;
    }

    /// Remove all elements.
    void clear()
    {
        foreach(c; children)
        {
            Delete(c);
        }

        children.free();
        length = 0;
    }

    ~this()
    {
        clear();
    }

    /// Trie must be manually freed when it's no longer needed.
    void free()
    {
        Delete(this);
    }
}

/// Convenient alias
alias Dict = Trie;

/// Convenient function for dict creation.
Dict!(T, K) dict(T, K)()
{
    return New!(Dict!(T, K))();
}

///
unittest
{
    auto d = dict!(string, string)();
    scope(exit) d.free();
    d["Hell"] = "No";
    d["Hello"] = "World";
    d["Help"] = "Me";
    d["Something"] = "Else";
    assert(d["Hell"] == "No");
    assert(d["Hello"] == "World");
    assert(d["Help"] == "Me");
    assert(d["Something"] == "Else");
    assert("Held" !in d);
    assert(d.length == 4);

    string[string] elements;
    foreach(key, value; d)
    {
        elements[key] = value;
    }
    assert(elements["Hell"] == "No");
    assert(elements["Hello"] == "World");
    assert(elements["Help"] == "Me");
    assert(elements["Something"] == "Else");
    assert(elements.length == d.length);

    d["Something"] = "New";
    assert(d["Something"] == "New");

    d.remove("Hell");
    assert(d.length == 3);
    assert(d.get("Hell") is null);

    d.clear();
    assert(d.length == 0);
    assert("Hello" !in d);
    assert("Help" !in d);
    assert("Something" !in d);

    d["Held"] = "Fire";
    assert(d["Held"] == "Fire");

    auto di = dict!(string, int);
    scope(exit) di.free();
    di[0xBEAF] = "BEAF";
    di[0xDEADBEAF] = "DEADBEAF";
    di[0xDEAD] = "DEAD";
    assert(di[0xBEAF] == "BEAF");
    assert(di[0xDEADBEAF] == "DEADBEAF");
    assert(di[0xDEAD] == "DEAD");
}


================================================
FILE: dlib/container/linkedlist.d
================================================
/*
Copyright (c) 2011-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Singly linked list
 *
 * Copyright: Timur Gafarov 2011-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Andrey Penechko, Roman Chistokhodov, ijet
 */
module dlib.container.linkedlist;

import dlib.core.memory;

/**
 * Element of single linked list.
 */
struct LinkedListElement(T)
{
    LinkedListElement!(T)* next = null;
    T datum;

    this(LinkedListElement!(T)* n)
    {
        next = n;
        datum = T.init;
    }
}

/**
 * GC-free single linked list implementation.
 */
struct LinkedList(T, bool ordered = true)
{
    ///Head of the list.
    LinkedListElement!(T)* head = null;
    
    ///Tail of the list.
    LinkedListElement!(T)* tail = null;
    
    ///Number of elements in the list.
    size_t length = 0;

    /**
     * Check if list has no elements.
     */
    @property bool empty()
    {
        return length == 0;
    }

    ///
    unittest
    {
        LinkedList!int list;
        assert(list.empty);
    }

    /**
     * Remove all elements and free used memory.
     */
    void free()
    {
        LinkedListElement!(T)* element = head;
        while (element !is null)
        {
            auto e = element;
            element = element.next;
            Delete(e);
        }
        head = null;
        tail = null;
        length = 0;
    }

    /**
     * Iterating over list via foreach.
     */
    int opApply(scope int delegate(size_t, ref T) dg)
    {
        int result = 0;
        uint index = 0;

        LinkedListElement!(T)* element = head;
        while (element !is null)
        {
            result = dg(index, element.datum);
            if (result)
                break;
            element = element.next;
            index++;
        }

        return result;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        list.append(1);
        list.append(2);
        list.append(3);
        list.append(4);

        int[4] values;

        foreach(size_t i, ref int val; list) {
            values[i] = val;
        }

        assert(values[] == [1,2,3,4]);
    }

    /**
     * Iterating over list via foreach.
     */
    int opApply(scope int delegate(ref T) dg)
    {
        int result = 0;

        LinkedListElement!(T)* element = head;
        while (element !is null)
        {
            result = dg(element.datum);
            if (result)
                break;
            element = element.next;
        }

        return result;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        list.append(1);
        list.append(2);
        list.append(3);
        list.append(4);

        int[] values;

        foreach(ref int val; list) {
            values ~= val;
        }

        assert(values[] == [1,2,3,4]);
    }

    /**
     * Appen value v to the end.
     * Returns: Pointer to added list element.
     */
    LinkedListElement!(T)* insertBack(T v)
    {
        length++;

        if (tail is null)
        {
            tail = New!(LinkedListElement!(T))(null);
            tail.datum = v;
        }
        else
        {
            tail.next = New!(LinkedListElement!(T))(null);
            tail.next.datum = v;
            tail = tail.next;
        }

        if (head is null) head = tail;

        return tail;
    }

    // Insert operator
    auto opCatAssign(T v)
    {
        insertBack(v);
        return this;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        auto element = list.append(13);
        assert(element.datum == 13);
        assert(list.length == 1);
        element = list.append(42);
        assert(element.datum == 42);
        assert(list.length == 2);
    }

    /**
     * Insert value v after element.
     * Returns: Pointer to inserted element.
     * Note: element must be not null.
     */
    LinkedListElement!(T)* insertAfter(LinkedListElement!(T)* element, T v)
    {
        length++;
        auto newElement = New!(LinkedListElement!(T))(null);
        newElement.datum = v;
        newElement.next = element.next;
        element.next = newElement;
        if (element is tail) tail = newElement;
        return newElement;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        auto first = list.append(1);
        auto last = list.append(2);
        list.insertAfter(first, 3);

        assert(list.length == 3);
        auto arr = list.toArray();
        assert(arr == [1,3,2]);
        Delete(arr);
    }

    /**
     * Insert value v at the beginning.
     */
    LinkedListElement!(T)* insertFront(T v)
    {
        length++;
        auto newElement = New!(LinkedListElement!(T))(null);
        newElement.datum = v;
        newElement.next = head;
        head = newElement;
        if (tail is null) {
            tail = head;
        }
        return newElement;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        list.insertBeginning(1);
        list.insertBack(2);
        list.insertBeginning(0);

        import std.algorithm : equal;
        assert(equal(list.byElement(), [0,1,2]));
    }

    /**
     * Remove value after element.
     * Note: element must be not null.
     */
    void removeAfter(LinkedListElement!(T)* element)
    {
        length--;
        auto obsolete = element.next;
        if (obsolete !is null)
        {
            if (obsolete is tail) tail = element;
            element.next = obsolete.next;
            Delete(obsolete);
        }
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        auto first = list.insertBack(1);
        auto second = list.insertBack(2);
        auto third = list.insertBack(3);
        list.removeAfter(first);

        import std.algorithm : equal;
        assert(equal(list.byElement(), [1,3]));
    }

    /**
     * Remove the first element.
     * Note: list must be non-empty.
     */
    void removeFront()
    {
        length--;
        auto obsolete = head;
        if (obsolete !is null)
        {
            head = obsolete.next;
            Delete(obsolete);
        }
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        list.insertBack(0);
        list.removeFront();
        assert(list.length == 0);

        list.insertBack(1);
        list.insertBack(2);
        list.insertBack(3);
        list.removeFront();
        assert(list.length == 2);
        import std.algorithm : equal;
        assert(equal(list.byElement(), [2,3]));
    }

    /**
     * Append other list.
     * Note: Appended list should not be freed. It becomes part of this list.
     */
    void appendList(LinkedList!(T) list)
    {
        length += list.length;
        if (tail !is null) {
            tail.next = list.head;
        }
        if (head is null) {
            head = list.head;
        }
        tail = list.tail;
    }

    ///
    unittest
    {
        LinkedList!int list1;
        scope(exit) list1.free();
        LinkedList!int list2;
        LinkedList!int list3;

        list2.insertBack(1);
        list2.insertBack(2);

        list1.appendList(list2);

        import std.algorithm : equal;
        assert(equal(list1.byElement(), [1,2]));

        list3.insertBack(3);
        list3.insertBack(4);
        list1.appendList(list3);

        assert(equal(list1.byElement(), [1,2,3,4]));
    }

    /**
     * Search for element with value v.
     * Returns: Found element or null if could not find.
     */
    LinkedListElement!(T)* find(T v)
    {
        LinkedListElement!(T)* element = head;
        LinkedListElement!(T)* prevElement = head;
        while (element !is null)
        {
            if (element.datum == v)
            {
                static if (!ordered)
                {
                   /*
                    * Move-to-front heuristic:
                    * Move an element to the beginning of the list once it is found.
                    * This scheme ensures that the most recently used items are also
                    * the quickest to find again.
                    */
                    prevElement.next = element.next;
                    element.next = head;
                    head = element;
                }

                return element;
            }

            prevElement = element;
            element = element.next;
        }

        return null;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        assert(list.find(42) is null);

        list.insertBack(13);
        list.insertBack(42);

        auto first = list.find(13);
        assert(first && first.datum == 13);

        auto second = list.find(42);
        assert(second && second.datum == 42);

        assert(list.find(0) is null);
    }

    /**
     * Convert to array.
     */
    T[] toArray()
    {
        T[] arr = New!(T[])(length);
        foreach(i, v; this)
            arr[i] = v;
        return arr;
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        list.insertBack(1);
        list.insertBack(2);
        list.insertBack(3);

        auto arr = list.toArray();
        assert(arr == [1,2,3]);
        Delete(arr);
    }

    auto byElement()
    {
        struct ByElement
        {
        private:
            LinkedListElement!(T)* _first;

        public:
            @property bool empty() {
                return _first is null;
            }

            @property T front() {
                return _first.datum;
            }

            void popFront() {
                _first = _first.next;
            }

            auto save() {
                return this;
            }
        }

        return ByElement(head);
    }

    ///
    unittest
    {
        LinkedList!int list;
        scope(exit) list.free();

        assert(list.byElement().empty);

        list.insertBack(1);
        list.insertBack(2);
        list.insertBack(3);

        auto range = list.byElement();
        import std.range: isInputRange;
        import std.algorithm: equal;
        static assert(isInputRange!(typeof(range)));

        assert(equal(range, [1, 2, 3]));

        range = list.byElement();
        auto saved = range.save();
        range.popFront();
        assert(equal(range, [2, 3]));
        assert(equal(saved, [1, 2, 3]));
    }

    // For backward compatibility
    alias append = insertBack;
    alias insertBeginning = insertFront;
    alias removeBeginning = removeFront;
    alias search = find;
}


================================================
FILE: dlib/container/mappedlist.d
================================================
/*
Copyright (c) 2018-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/** 
 * A list with string-mapped indices.
 *
 * Copyright: Timur Gafarov 2018-2025.
 * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.container.mappedlist;

import dlib.core.ownership;
import dlib.core.memory;
import dlib.container.array;
import dlib.container.dict;

/**
 * A list with string-mapped indices.
 */
class MappedList(T): Owner
{
    Array!T data;
    Dict!(size_t, string) indices;

    this(Owner owner)
    {
        super(owner);
        indices = New!(Dict!(size_t, string))();
    }

    void set(string name, T val)
    {
        data.append(val);
        indices[name] = data.length - 1;
    }

    T get(string name)
    {
        return data[indices[name]];
    }

    ~this()
    {
        data.free();
        Delete(indices);
    }
}


================================================
FILE: dlib/container/package.d
================================================
/*
Copyright (c) 2013-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Containers
 *
 * Description:
 * This package implements generic GC-free data containers, such as linked list, 
 * dynamic array, dictionary, etc. They are based on dlib.core.memory allocators.
 * dlib.container is useful when writing applications with manual memory management.
 *
 * Copyright: Timur Gafarov 2013-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.container;

public
{
    import dlib.container.array;
    import dlib.container.buffer;
    import dlib.container.bst;
    import dlib.container.dict;
    import dlib.container.linkedlist;
    import dlib.container.mappedlist;
    import dlib.container.queue;
    import dlib.container.stack;
    import dlib.container.spscqueue;
}


================================================
FILE: dlib/container/queue.d
================================================
/*
Copyright (c) 2011-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Queue (based on linked list)
 *
 * Copyright: Timur Gafarov 2011-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Andrey Penechko, Roman Chistokhodov
 */
module dlib.container.queue;

import dlib.container.array;

/**
 * Queue implementation based on Array.
 */
struct Queue(T)
{
    private:
    Array!T array;

    public:
    /**
     * Check if stack has no elements.
     */
    @property bool empty()
    {
        return array.length == 0;
    }

    /**
     * Add element to queue.
     */
    void enqueue(const(T) v)
    {
        array.insertBack(v);
    }

    /**
     * Remove element from queue.
     * Returns: Removed element.
     * Throws: Exception if queue is empty.
     */
    T dequeue()
    {
        if (empty)
            throw new Exception("Queue!(T): queue is empty");

        T res = array[0];
        array.removeFront(1);
        return res;
    }

    /**
     * Non-throwing version of dequeue.
     * Returns: true on success, false on failure.
     * Element is stored in value.
     */
    bool dequeue(ref T value) nothrow
    {
        if (empty)
            return false;

        value = array[0];
        array.removeFront(1);
        return true;
    }

    /**
     * Free memory allocated by Queue.
     */
    void free()
    {
        array.free();
    }
}

///
unittest
{
    import std.exception: assertThrown;

    Queue!int q;
    assertThrown(q.dequeue());
    assert(q.empty);

    q.enqueue(50);
    q.enqueue(30);
    q.enqueue(900);

    int v;
    q.dequeue(v);
    assert(v == 50);
    assert(q.dequeue() == 30);
    assert(q.dequeue() == 900);
    assert(q.empty);

    q.free();
}


================================================
FILE: dlib/container/spscqueue.d
================================================
/*
Copyright (c) 2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Wait-free single-producer single-consumer queue.
 *
 * Copyright: Timur Gafarov 2025
 * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.container.spscqueue;

import core.atomic;

import dlib.core.memory;
import dlib.core.ownership;
import dlib.core.thread;
import dlib.container.array;

/**
 * Generic, wait-free single-producer single-consumer queue.
 *
 * Params:
 *   T = element type.
 *   capacity = Maximum number of elements in the queue.
 */
struct SPSCQueue(T, size_t capacity)
{
    /// Circular buffer.
    T[capacity] buffer;

    /// Producer write index.
    shared size_t head = 0;
    
    /// Consumer read index.
    shared size_t tail = 0;

    /// Add an element to the queue. Returns false if full.
    bool push(T value)
    {
        auto next = (head + 1) % capacity;
        if (next == tail) // queue full
            return false;

        buffer[head] = value;
        atomicStore!(MemoryOrder.rel)(head, next);
        return true;
    }

    /// Remove an element from the queue. Returns false if empty.
    bool pop(out T value)
    {
        if (tail == atomicLoad!(MemoryOrder.acq)(head))
            return false; // queue empty

        value = buffer[tail];
        tail = (tail + 1) % capacity;
        return true;
    }
}


================================================
FILE: dlib/container/stack.d
================================================
/*
Copyright (c) 2011-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Stack (based on Array)
 *
 * Copyright: Timur Gafarov 2011-2025.
 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov, Andrey Penechko, Roman Chistokhodov
 */
module dlib.container.stack;

import dlib.container.array;

/**
 * Stack implementation based on Array.
 */
struct Stack(T)
{
    private Array!T array;

    public:
    /**
     * Push element to stack.
     */
    void push(T v)
    {
        array.insertBack(v);
    }

    /**
     * Pop top element out.
     * Returns: Removed element.
     * Throws: Exception on underflow.
     */
    T pop()
    {
        if (empty)
            throw new Exception("Stack!(T): underflow");

        T res = array[$-1];
        array.removeBack(1);
        return res;
    }

    /**
     * Non-throwing version of pop.
     * Returns: true on success, false on failure.
     * Element is stored in value.
     */
    bool pop(ref T value)
    {
        if (empty)
            return false;

        value = array[$-1];
        array.removeBack(1);
        return true;
    }

    /**
     * Top stack element.
     * Note: Stack must be non-empty.
     */
    T top()
    {
        return array[$-1];
    }

    /**
     * Pointer to top stack element.
     * Note: Stack must be non-empty.
     */
    T* topPtr()
    {
        return &array.data[$-1];
    }

    /**
     * Check if stack has no elements.
     */
    @property bool empty() nothrow
    {
        return array.length == 0;
    }

    /**
     * Free memory allocated by Stack.
     */
    void free()
    {
        array.free();
    }
}

///
unittest
{
    import std.exception: assertThrown;

    Stack!int s;
    assertThrown(s.pop());
    s.push(100);
    s.push(3);
    s.push(76);
    assert(s.top() == 76);
    int v;
    s.pop(v);
    assert(v == 76);
    assert(s.pop() == 3);
    assert(s.pop() == 100);
    assert(s.empty);
    s.free();
}


================================================
FILE: dlib/core/bitio.d
================================================
/*
Copyright (c) 2015-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/**
 * Bit-level manipulations
 *
 * Copyright: Timur Gafarov 2015-2025.
 * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Timur Gafarov
 */
module dlib.core.bitio;
 
/**
 * Endianness
 */
enum Endian
{
    Little,
    Big
}

/**
 * Returns high 4 bits of a byte
 */
T hiNibble(T)(T b)
{
    return ((b >> 4) & 0x0F);
}

///
unittest
{
    assert(hiNibble(0xFE) == 0x0F);
}

/**
 * Returns low 4 bits of a byte
 */
T loNibble(T)(T b)
{
    return (b & 0x0F);
}

///
unittest
{
    assert(loNibble(0xFE) == 0x0E);
}

/**
 * Sets bit at position pos in integer b to state
 */
T setBit(T)(T b, uint pos, bool state)
{
    if (state)
        return cast(T)(b | (1 << pos));
    else
        return cast(T)(b & ~(1 << pos));
}

///
unittest
{
    assert(setBit(0, 0, true) == 1);
    assert(setBit(1, 0, false) == 0);
}

/**
 * Returns bit at position pos in integer b
 */
bool getBit(T)(T b, uint pos)
{
    return ((b & (1 << pos)) != 0);
}

///
unittest
{
    assert(getBit(1, 0) == 1);
}


================================================
FILE: dlib/core/compound.d
================================================
/*
Copyright (c) 2011-2025 Timur Gafarov

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY D
Download .txt
gitextract_13402xs3/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── test.yml
├── .gitignore
├── AUTHORS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── COPYING.md
├── Doxyfile
├── README.md
├── dlib/
│   ├── audio/
│   │   ├── io/
│   │   │   ├── package.d
│   │   │   └── wav.d
│   │   ├── package.d
│   │   ├── sample.d
│   │   ├── sound.d
│   │   ├── synth.d
│   │   └── unmanaged.d
│   ├── coding/
│   │   ├── package.d
│   │   ├── varint.d
│   │   └── zlib.d
│   ├── concurrency/
│   │   ├── package.d
│   │   ├── taskqueue.d
│   │   ├── threadpool.d
│   │   └── workerthread.d
│   ├── container/
│   │   ├── array.d
│   │   ├── bst.d
│   │   ├── buffer.d
│   │   ├── dict.d
│   │   ├── linkedlist.d
│   │   ├── mappedlist.d
│   │   ├── package.d
│   │   ├── queue.d
│   │   ├── spscqueue.d
│   │   └── stack.d
│   ├── core/
│   │   ├── bitio.d
│   │   ├── compound.d
│   │   ├── memory.d
│   │   ├── mutex.d
│   │   ├── oop.d
│   │   ├── ownership.d
│   │   ├── package.d
│   │   ├── stream.d
│   │   ├── thread.d
│   │   └── tuple.d
│   ├── filesystem/
│   │   ├── delegaterange.d
│   │   ├── dirrange.d
│   │   ├── filesystem.d
│   │   ├── local.d
│   │   ├── package.d
│   │   ├── posix/
│   │   │   ├── common.d
│   │   │   ├── directory.d
│   │   │   └── file.d
│   │   ├── stdfs.d
│   │   ├── stdposixdir.d
│   │   ├── stdwindowsdir.d
│   │   └── windows/
│   │       ├── common.d
│   │       ├── directory.d
│   │       └── file.d
│   ├── geometry/
│   │   ├── aabb.d
│   │   ├── frustum.d
│   │   ├── intersection.d
│   │   ├── mpr.d
│   │   ├── obb.d
│   │   ├── package.d
│   │   ├── plane.d
│   │   ├── ray.d
│   │   ├── sphere.d
│   │   ├── support.d
│   │   ├── triangle.d
│   │   ├── trimesh.d
│   │   └── utils.d
│   ├── image/
│   │   ├── animation.d
│   │   ├── arithmetics.d
│   │   ├── canvas.d
│   │   ├── color.d
│   │   ├── filters/
│   │   │   ├── binarization.d
│   │   │   ├── boxblur.d
│   │   │   ├── chromakey.d
│   │   │   ├── contrast.d
│   │   │   ├── convolution.d
│   │   │   ├── desaturate.d
│   │   │   ├── edgedetect.d
│   │   │   ├── histogram.d
│   │   │   ├── lens.d
│   │   │   ├── median.d
│   │   │   ├── morphology.d
│   │   │   ├── normalmap.d
│   │   │   ├── package.d
│   │   │   └── sharpen.d
│   │   ├── fthread.d
│   │   ├── hdri.d
│   │   ├── hsv.d
│   │   ├── image.d
│   │   ├── io/
│   │   │   ├── bmp.d
│   │   │   ├── hdr.d
│   │   │   ├── jpeg.d
│   │   │   ├── package.d
│   │   │   ├── png.d
│   │   │   ├── tga.d
│   │   │   └── utils.d
│   │   ├── package.d
│   │   ├── render/
│   │   │   ├── cosplasma.d
│   │   │   ├── package.d
│   │   │   ├── shapes.d
│   │   │   └── text.d
│   │   ├── resampling/
│   │   │   ├── bicubic.d
│   │   │   ├── bilinear.d
│   │   │   ├── lanczos.d
│   │   │   ├── nearest.d
│   │   │   └── package.d
│   │   ├── signal2d.d
│   │   ├── transform.d
│   │   └── unmanaged.d
│   ├── math/
│   │   ├── combinatorics.d
│   │   ├── complex.d
│   │   ├── decomposition.d
│   │   ├── diff.d
│   │   ├── dual.d
│   │   ├── dualquaternion.d
│   │   ├── fft.d
│   │   ├── hof.d
│   │   ├── interpolation/
│   │   │   ├── bezier.d
│   │   │   ├── catmullrom.d
│   │   │   ├── easing.d
│   │   │   ├── hermite.d
│   │   │   ├── linear.d
│   │   │   ├── nearest.d
│   │   │   ├── package.d
│   │   │   └── smoothstep.d
│   │   ├── linsolve.d
│   │   ├── matrix.d
│   │   ├── package.d
│   │   ├── quaternion.d
│   │   ├── sse.d
│   │   ├── tensor.d
│   │   ├── transformation.d
│   │   ├── utils.d
│   │   └── vector.d
│   ├── memory/
│   │   ├── allocator.d
│   │   ├── arena.d
│   │   ├── gcallocator.d
│   │   ├── mallocator.d
│   │   ├── mmappool.d
│   │   └── package.d
│   ├── network/
│   │   ├── errno.d
│   │   ├── package.d
│   │   ├── socket.d
│   │   └── url.d
│   ├── package.d
│   ├── random/
│   │   ├── package.d
│   │   └── random.d
│   ├── serialization/
│   │   ├── json.d
│   │   ├── package.d
│   │   └── xml.d
│   └── text/
│       ├── common.d
│       ├── encodings.d
│       ├── lexer.d
│       ├── package.d
│       ├── str.d
│       ├── utf16.d
│       ├── utf8.d
│       └── utils.d
└── dub.json
Condensed preview — 164 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,221K chars).
[
  {
    "path": ".editorconfig",
    "chars": 531,
    "preview": "root = true\n\n[*.{c,h,d,di,dd,sh}]\nend_of_line = crlf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntr"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 40,
    "preview": "patreon: gecko0307\nliberapay: gecko0307\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 764,
    "preview": "name: CI\n\non: \n  push:\n    branches: [ master ]\n    paths:\n    - 'dlib/**'\n    - 'dub.json'\n    - '.github/workflows/**'"
  },
  {
    "path": ".gitignore",
    "chars": 316,
    "preview": "# Compiled Object files\n*.o\n*.obj\n\n# Compiled Static libraries\n*.a\n*.lib\n\n# Executables\n*.exe\n\n# Dub files\n.dub\ndub.sele"
  },
  {
    "path": "AUTHORS.md",
    "chars": 1699,
    "preview": "# dlib authors and contributors\n* Core library - [Timur Gafarov aka gecko0307](https://github.com/gecko0307)\n* Filesyste"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 41147,
    "preview": "dlib 1.5.0 - TBD\n----------------\n- **dlib.math**\n  - `trsMatrix` that creates a transformation matrix from translation/"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 1089,
    "preview": "# Code of Conduct\n\nThis project welcomes contributions in any form and encourages open discussion and exchange of views "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 6237,
    "preview": "# Contributing Guidelines\n\n#### Bug reporting \n\nOpen an issue at [GitHub issue tracker](https://github.com/gecko0307/dli"
  },
  {
    "path": "COPYING.md",
    "chars": 1361,
    "preview": "Boost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is hereby granted, free of charge, to any person "
  },
  {
    "path": "Doxyfile",
    "chars": 629,
    "preview": "DOXYFILE_ENCODING      = UTF-8\nPROJECT_NAME           = \"dlib\"\nPROJECT_NUMBER         = 1.1\nPROJECT_BRIEF          = \"Al"
  },
  {
    "path": "README.md",
    "chars": 6788,
    "preview": "<img align=\"left\" alt=\"dlib logo\" src=\"https://github.com/gecko0307/dlib/raw/master/logo/dlib-logo.png\" height=\"66\" />\n\n"
  },
  {
    "path": "dlib/audio/io/package.d",
    "chars": 2519,
    "preview": "/*\nCopyright (c) 2022-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/audio/io/wav.d",
    "chars": 6336,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/audio/package.d",
    "chars": 2036,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/audio/sample.d",
    "chars": 3609,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/audio/sound.d",
    "chars": 8197,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/audio/synth.d",
    "chars": 7796,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/audio/unmanaged.d",
    "chars": 3319,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/coding/package.d",
    "chars": 1703,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/coding/varint.d",
    "chars": 3481,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/coding/zlib.d",
    "chars": 5429,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/concurrency/package.d",
    "chars": 1732,
    "preview": "/*\nCopyright (c) 2019-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/concurrency/taskqueue.d",
    "chars": 2968,
    "preview": "/*\nCopyright (c) 2019-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/concurrency/threadpool.d",
    "chars": 3935,
    "preview": "/*\nCopyright (c) 2019-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/concurrency/workerthread.d",
    "chars": 2309,
    "preview": "/*\nCopyright (c) 2019-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/container/array.d",
    "chars": 16919,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/bst.d",
    "chars": 4703,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/buffer.d",
    "chars": 19393,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is "
  },
  {
    "path": "dlib/container/dict.d",
    "chars": 8163,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/linkedlist.d",
    "chars": 12633,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/mappedlist.d",
    "chars": 2211,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\nPermission is hereby "
  },
  {
    "path": "dlib/container/package.d",
    "chars": 2207,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/queue.d",
    "chars": 3211,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/container/spscqueue.d",
    "chars": 2713,
    "preview": "/*\nCopyright (c) 2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby gran"
  },
  {
    "path": "dlib/container/stack.d",
    "chars": 3440,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/bitio.d",
    "chars": 2513,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/compound.d",
    "chars": 2434,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/memory.d",
    "chars": 11245,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/mutex.d",
    "chars": 4363,
    "preview": "/*\nCopyright (c) 2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby gran"
  },
  {
    "path": "dlib/core/oop.d",
    "chars": 4475,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/ownership.d",
    "chars": 4040,
    "preview": "/*\r\nCopyright (c) 2017-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/package.d",
    "chars": 1932,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/stream.d",
    "chars": 10995,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/core/thread.d",
    "chars": 6911,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/core/tuple.d",
    "chars": 2839,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/filesystem/delegaterange.d",
    "chars": 2845,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/dirrange.d",
    "chars": 1801,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPe"
  },
  {
    "path": "dlib/filesystem/filesystem.d",
    "chars": 8474,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPe"
  },
  {
    "path": "dlib/filesystem/local.d",
    "chars": 15353,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/package.d",
    "chars": 1835,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPe"
  },
  {
    "path": "dlib/filesystem/posix/common.d",
    "chars": 1941,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/posix/directory.d",
    "chars": 3154,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/posix/file.d",
    "chars": 3566,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/stdfs.d",
    "chars": 18622,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/filesystem/stdposixdir.d",
    "chars": 4101,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/filesystem/stdwindowsdir.d",
    "chars": 5802,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/filesystem/windows/common.d",
    "chars": 2129,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/windows/directory.d",
    "chars": 3742,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/filesystem/windows/file.d",
    "chars": 4352,
    "preview": "/*\r\nCopyright (c) 2014-2025 Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is her"
  },
  {
    "path": "dlib/geometry/aabb.d",
    "chars": 6743,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/frustum.d",
    "chars": 5643,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/intersection.d",
    "chars": 11501,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/mpr.d",
    "chars": 8952,
    "preview": "/*\nCopyright (c) 2013-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/geometry/obb.d",
    "chars": 2325,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/package.d",
    "chars": 2033,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/plane.d",
    "chars": 6438,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/ray.d",
    "chars": 5431,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/sphere.d",
    "chars": 2110,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/support.d",
    "chars": 5029,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/geometry/triangle.d",
    "chars": 5663,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/trimesh.d",
    "chars": 8064,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/geometry/utils.d",
    "chars": 4192,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/animation.d",
    "chars": 10515,
    "preview": "/*\r\nCopyright (c) 2017-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/arithmetics.d",
    "chars": 4765,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/canvas.d",
    "chars": 12737,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/image/color.d",
    "chars": 7602,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/binarization.d",
    "chars": 3571,
    "preview": "/*\r\nCopyright (c) 2018-2025 Oleg Baharev, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nP"
  },
  {
    "path": "dlib/image/filters/boxblur.d",
    "chars": 2530,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/chromakey.d",
    "chars": 5642,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/contrast.d",
    "chars": 2647,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/image/filters/convolution.d",
    "chars": 4739,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/desaturate.d",
    "chars": 2584,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/edgedetect.d",
    "chars": 4458,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov, Oleg Baharev\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nP"
  },
  {
    "path": "dlib/image/filters/histogram.d",
    "chars": 2608,
    "preview": "/*\r\nCopyright (c) 2018-2025 Oleg Baharev, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nP"
  },
  {
    "path": "dlib/image/filters/lens.d",
    "chars": 3041,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/median.d",
    "chars": 3223,
    "preview": "/*\nCopyright (c) 2022-2025 Oleg Baharev, Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermis"
  },
  {
    "path": "dlib/image/filters/morphology.d",
    "chars": 5398,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/normalmap.d",
    "chars": 3629,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/filters/package.d",
    "chars": 2113,
    "preview": "/*\nCopyright (c) 2020-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/image/filters/sharpen.d",
    "chars": 2289,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/fthread.d",
    "chars": 2596,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/hdri.d",
    "chars": 10917,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/hsv.d",
    "chars": 5133,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/image.d",
    "chars": 18898,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/io/bmp.d",
    "chars": 33237,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov, Roman Chistokhodov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 200"
  },
  {
    "path": "dlib/image/io/hdr.d",
    "chars": 12293,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/io/jpeg.d",
    "chars": 43490,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/io/package.d",
    "chars": 4683,
    "preview": "/*\nCopyright (c) 2014-2025 Timur Gafarov, Martin Cejp\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermiss"
  },
  {
    "path": "dlib/image/io/png.d",
    "chars": 44119,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov, Martin Cejp, Vadim Lopatin\r\n\r\nBoost Software License - Version 1.0 - August 1"
  },
  {
    "path": "dlib/image/io/tga.d",
    "chars": 10577,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov, Roman Chistokhodov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 200"
  },
  {
    "path": "dlib/image/io/utils.d",
    "chars": 2579,
    "preview": "/*\r\nCopyright (c) 2014-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/package.d",
    "chars": 2094,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/render/cosplasma.d",
    "chars": 2103,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/render/package.d",
    "chars": 1702,
    "preview": "/*\nCopyright (c) 2022-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/image/render/shapes.d",
    "chars": 4138,
    "preview": "/*\r\nCopyright (c) 2015-2025 Oleg Baharev, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nP"
  },
  {
    "path": "dlib/image/render/text.d",
    "chars": 11222,
    "preview": "/*\nCopyright (c) 2022-2025 Oleg Baharev, Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermis"
  },
  {
    "path": "dlib/image/resampling/bicubic.d",
    "chars": 3575,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/resampling/bilinear.d",
    "chars": 3707,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/resampling/lanczos.d",
    "chars": 3609,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/resampling/nearest.d",
    "chars": 2359,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/resampling/package.d",
    "chars": 1767,
    "preview": "/*\nCopyright (c) 2022-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/image/signal2d.d",
    "chars": 6767,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/transform.d",
    "chars": 3921,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/image/unmanaged.d",
    "chars": 4907,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/combinatorics.d",
    "chars": 5069,
    "preview": "/*\r\nCopyright (c) 2015-2025 Nick Papanastasiou, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 200"
  },
  {
    "path": "dlib/math/complex.d",
    "chars": 5990,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/decomposition.d",
    "chars": 2947,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/diff.d",
    "chars": 1936,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/dual.d",
    "chars": 5632,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/dualquaternion.d",
    "chars": 5793,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/fft.d",
    "chars": 3446,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/hof.d",
    "chars": 3780,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/bezier.d",
    "chars": 3727,
    "preview": "/*\nCopyright (c) 2013-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/catmullrom.d",
    "chars": 2187,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/easing.d",
    "chars": 3037,
    "preview": "/*\nCopyright (c) 2019-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/hermite.d",
    "chars": 2230,
    "preview": "/*\nCopyright (c) 2013-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/linear.d",
    "chars": 1804,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/nearest.d",
    "chars": 1834,
    "preview": "/*\nCopyright (c) 2011-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/package.d",
    "chars": 1909,
    "preview": "/*\nCopyright (c) 2020-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/interpolation/smoothstep.d",
    "chars": 2275,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/math/linsolve.d",
    "chars": 3521,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/matrix.d",
    "chars": 31707,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov, Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPe"
  },
  {
    "path": "dlib/math/package.d",
    "chars": 2520,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/quaternion.d",
    "chars": 19809,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/sse.d",
    "chars": 16392,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov, Alexander Perfilyev\r\n\r\nBoost Software License - Version 1.0 - August 17th, 20"
  },
  {
    "path": "dlib/math/tensor.d",
    "chars": 14724,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/transformation.d",
    "chars": 20208,
    "preview": "/*\r\nCopyright (c) 2013-2025 Timur Gafarov, Martin Cejp\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPe"
  },
  {
    "path": "dlib/math/utils.d",
    "chars": 8146,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/math/vector.d",
    "chars": 31182,
    "preview": "/*\r\nCopyright (c) 2011-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/memory/allocator.d",
    "chars": 3754,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is "
  },
  {
    "path": "dlib/memory/arena.d",
    "chars": 17337,
    "preview": "/*\nCopyright (c) 2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\nPermission is hereby grant"
  },
  {
    "path": "dlib/memory/gcallocator.d",
    "chars": 2767,
    "preview": "/*\r\nCopyright (c) 2017-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/memory/mallocator.d",
    "chars": 4944,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is "
  },
  {
    "path": "dlib/memory/mmappool.d",
    "chars": 15096,
    "preview": "/*\nCopyright (c) 2016-2025 Eugene Wissner\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereb"
  },
  {
    "path": "dlib/memory/package.d",
    "chars": 2098,
    "preview": "/*\nCopyright (c) 2016-2025 Eugene Wissner\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereb"
  },
  {
    "path": "dlib/network/errno.d",
    "chars": 2342,
    "preview": "/*\nCopyright (c) 2020-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/network/package.d",
    "chars": 1747,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner, Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r"
  },
  {
    "path": "dlib/network/socket.d",
    "chars": 43686,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is "
  },
  {
    "path": "dlib/network/url.d",
    "chars": 40486,
    "preview": "/*\r\nCopyright (c) 2016-2025 Eugene Wissner\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is "
  },
  {
    "path": "dlib/package.d",
    "chars": 4727,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/random/package.d",
    "chars": 1442,
    "preview": "/*\nCopyright (c) 2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby gran"
  },
  {
    "path": "dlib/random/random.d",
    "chars": 2563,
    "preview": "/*\nCopyright (c) 2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby gran"
  },
  {
    "path": "dlib/serialization/json.d",
    "chars": 8559,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/serialization/package.d",
    "chars": 1701,
    "preview": "/*\r\nCopyright (c) 2017-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/serialization/xml.d",
    "chars": 20658,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/text/common.d",
    "chars": 1520,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/text/encodings.d",
    "chars": 2841,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/text/lexer.d",
    "chars": 9495,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/text/package.d",
    "chars": 1791,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/text/str.d",
    "chars": 6082,
    "preview": "/*\nCopyright (c) 2018-2025 Timur Gafarov\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby"
  },
  {
    "path": "dlib/text/utf16.d",
    "chars": 7657,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/text/utf8.d",
    "chars": 8480,
    "preview": "/*\r\nCopyright (c) 2015-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dlib/text/utils.d",
    "chars": 2711,
    "preview": "/*\r\nCopyright (c) 2016-2025 Timur Gafarov\r\n\r\nBoost Software License - Version 1.0 - August 17th, 2003\r\n\r\nPermission is h"
  },
  {
    "path": "dub.json",
    "chars": 962,
    "preview": "{\n    \"name\": \"dlib\",\n    \"description\": \"D language utility library\",\n    \"homepage\": \"http://github.com/gecko0307/dlib"
  }
]

About this extraction

This page contains the full source code of the gecko0307/dlib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 164 files (1.1 MB), approximately 298.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!