36 Commits

Author SHA1 Message Date
b023146cb3 Update contributing guidelines 2017-10-21 14:36:34 +02:00
d1d55be7c2 Fix lowerHexDigits string 2017-10-18 06:40:22 +02:00
7b21238db7 String: Fix byCodePoint.popFront for multibyte chars 2017-10-14 13:47:16 +02:00
e316631f6e Add test package 2017-10-12 07:41:35 +02:00
fdf902c755 Update dmd 2.076 to 2.076.1 2017-10-10 07:03:04 +02:00
5d6f8e5299 Implement pure onOutOfMemory 2017-10-10 06:59:34 +02:00
87bfd77373 container.string: Add missing postblit 2017-10-08 15:53:29 +02:00
17005e4ac9 Fix isInnerClass for templates, sort unittest attributes 2017-10-06 12:28:14 +02:00
85ad88bc4d Rename isPolymorphic into isPolymorphicType 2017-10-06 12:06:47 +02:00
211f590caa Tests and better documentation for memory.stateSize 2017-10-06 07:45:46 +02:00
2f4dd34582 Replace isInterface, isClass, isStruct with isPolymorphic 2017-10-05 07:12:27 +02:00
7e93bcdeeb meta: Add canFind and isInnerClass 2017-10-04 06:06:26 +02:00
e4cd57a615 math.nbtheory: Implement natural logarithm 2017-10-02 14:55:30 +02:00
74b085b88d Sort imports 2017-10-01 19:03:42 +02:00
a576c36d02 Replace memcpy/memmove with copy/copyBackward 2017-09-30 08:15:02 +02:00
1056a2984e Fix #303
Allocation schema is displayed incorrectly in HTML.
Add pre-tag for the schema.
2017-09-27 17:56:15 +02:00
faebf3e4d5 Fix #304
Replace inline assembly with GAS.
2017-09-26 08:26:12 +02:00
20e7df386b Ignore dub_platform_probe- files 2017-09-25 07:51:03 +02:00
15d9cda755 Add info about supporting GDC 2017-09-24 18:08:47 +02:00
ee48c25328 Replace "Ditto." with "ditto"
ddox doesn't recognize "Ditto.".
2017-09-22 04:08:50 +02:00
4612d5eb6d Add tanya.encoding.ascii 2017-09-21 06:57:49 +02:00
8d3a4860e6 Add memory.op.find for looking for a byte in a memory block 2017-09-20 08:31:54 +02:00
3df6c83376 Move formatting development to the io branch 2017-09-19 15:10:24 +02:00
7445d42ad4 Add thrd_current for x86-64 linux 2017-09-19 06:16:43 +02:00
14f91b6942 Don't import math submodules publically 2017-09-18 12:28:13 +02:00
be551e9349 Add docs and tests for fp classificators 2017-09-18 11:31:37 +02:00
586d12b6c7 Classificators for double extended floating point numbers 2017-09-17 10:30:12 +02:00
27146f7e0c Add tanya.math.fp 2017-09-16 22:35:31 +02:00
9b54017840 Move all windows specific definitions from network.socket to the sys-package 2017-09-15 10:58:23 +02:00
aabb6334be Import extern windows fill/copy memory functions 2017-09-14 18:49:13 +02:00
ce425b9ce5 Move simple socket definitions to sys.windows 2017-09-14 07:31:26 +02:00
3e9ca359da math: Add floating point support to abs 2017-09-13 06:43:49 +02:00
3705cf387e Add syscalls to x86-64 linux 2017-09-12 06:23:28 +02:00
edc3296083 Drop support for dmd 2.073.2, remove deprecations 2017-09-12 06:07:16 +02:00
e8143bd0cc Fix template constraints style in tanya.math 2017-09-11 06:48:47 +02:00
3eb8618c32 Add range.primitive 2017-09-10 10:35:05 +02:00
60 changed files with 4655 additions and 3522 deletions

4
.gitignore vendored
View File

@ -7,8 +7,12 @@
__test__*__ __test__*__
__test__*__.core __test__*__.core
/tanya-test-* /tanya-test-*
/dub_platform_probe-*
/docs/ /docs/
/docs.json /docs.json
/*.lst /*.lst
# Ninja build
.ninja_*

View File

@ -7,10 +7,9 @@ os:
language: d language: d
d: d:
- dmd-2.076.0 - dmd-2.076.1
- dmd-2.075.1 - dmd-2.075.1
- dmd-2.074.1 - dmd-2.074.1
- dmd-2.073.2
env: env:
matrix: matrix:
@ -23,7 +22,7 @@ addons:
- gcc-multilib - gcc-multilib
before_script: before_script:
- if [ "$PS1" = '(dmd-2.076.0)' ]; then - if [ "$PS1" = '(dmd-2.076.1)' ]; then
export UNITTEST="unittest-cov"; export UNITTEST="unittest-cov";
fi fi

View File

@ -1,3 +1,4 @@
# Contributing # Contributing
Tanya is a project in active development, therefore any help is appreciated. Thank you for considering contributing Tanya is a project in active development, therefore any help is appreciated. Thank you for considering contributing
@ -7,9 +8,9 @@ These guidelines describe ways to get started.
## Ways to get involved ## Ways to get involved
* **Reporting a problem**: [Report](https://issues.caraus.io/projects/tanya/issues) bugs and usage problems you * **Reporting a problem**: [Report](https://github.com/caraus-ecms/tanya/issues) bugs and usage problems you
encounter. encounter.
* **Fixing issues**: [The bug tracker](https://issues.caraus.io/projects/tanya/issues) contains a list of issues you * **Fixing issues**: [The bug tracker](https://github.com/caraus-ecms/tanya/issues) contains a list of issues you
can work on. can work on.
* **Documentation**: You can improve API documentation by correcting grammar errors, completing existing texts and * **Documentation**: You can improve API documentation by correcting grammar errors, completing existing texts and
writing new ones, or providing usage examples. writing new ones, or providing usage examples.
@ -21,21 +22,14 @@ and implement this.
## Opening an issue ## Opening an issue
If you have found a bug, an error, have some question, or suggestion, open in issue. I'll try to answer as soon If you have found a bug, an error, have some question, or suggestion,
as I can. Tanya uses an external [Open an issue](https://github.com/caraus-ecms/tanya/issues). I'll try to answer as soon as I can. There is also a
[bug tracker](https://issues.caraus.io/projects/tanya/issues). You should list of open issues that mirror the current development process and progress. If you're looking for a challenge, just
[register](https://issues.caraus.io/account/register) before you can report your issue. There is also a list
of open issues that mirror the current development process and progress. If you're looking for a challenge, just
pick an issue you are interested in and start working on it. Fill free to comment on the issue to get more pick an issue you are interested in and start working on it. Fill free to comment on the issue to get more
information. information.
Some issues have a category assigned to them. Such issues belong mostly to a larger part of the library that is You can also look at the [milestones](https://github.com/Dlackware/gnome/milestones) to see what is planned for a
currently in development. The category specifies then the git branch development happens on. The remaining issues specific release.
can be fixed directly in master.
In the [roadmap](https://issues.caraus.io/projects/tanya/roadmap) you can find a list of issues that are planned
to be fixed till a specific release. Version numbers refer to the versions in the
[git repository](https://github.com/caraus-ecms/tanya/releases).
## Contribution process ## Contribution process
@ -44,7 +38,7 @@ to be fixed till a specific release. Version numbers refer to the versions in th
I accept GitHub pull requests. Creating a pull request is like sending a patch with the suggested change. I accept GitHub pull requests. Creating a pull request is like sending a patch with the suggested change.
First you have to [fork](https://guides.github.com/activities/forking/) the repository. Clone your fork locally First you have to [fork](https://guides.github.com/activities/forking/) the repository. Clone your fork locally
with `git clone` and create a new branch where you want to work, for example: with `git clone` and create a new branch where you want to work. For example:
```shell ```shell
git checkout -b bugfix-x git checkout -b bugfix-x
@ -61,32 +55,53 @@ described on GitHub to finish the process. See
[Using Pull Requests](https://help.github.com/articles/about-pull-requests/) for more information. [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) for more information.
Please ensure that your fork is even with the upstream (original) repository. If not, you have to rebase your branch Please ensure that your fork is even with the upstream (original) repository. If not, you have to rebase your branch
on upstream/master before submitting a pull request. See https://help.github.com/articles/syncing-a-fork/ for a on upstream/master before submitting the pull request. See [Syncing a fork](https://help.github.com/articles/syncing-a-fork/) for a
step-by-step guide. step-by-step guide.
### Fixing a bug ### Fixing a bug
Add an unittest that demonstrates the bug along with a short description: Add a unit test that demonstrates the bug along with a short description or link to the original bug.
```d
// Issue ###: https://issues.caraus.io/issues/###.
private unittest
{
}
```
### Adding new features ### Adding new features
* Use Ddoc to document the feature. * Use Ddoc to document the feature.
* Add some unittests that prevent new bugs and demonstrate how the feature is supposed to work. * Add some unit tests to prevent bugs.
* [Documented D unit tests](https://dlang.org/spec/ddoc.html#using_ddoc_to_generate_examples) go into the documentation and can be used as an usage
example. These tests should be readable and not complicated since they demonstrate how the feature is supposed to work.
* More advanced tests should be put into a separate not documented unittest block.
### Writing unit tests
```d
///
unittest
{
// A documented unit test has three slashes in front of it.
}
// Issue ##: https://github.com/caraus-ecms/tanya/issues/##.
unittest
{
// Not documented unit test may still have a description.
}
```
### Style guide ### Style guide
Make sure your changes follow [The D Style](https://dlang.org/dstyle.html) (including Make sure your changes follow [The D Style](https://dlang.org/dstyle.html) (including
[Additional Requirements for Phobos](https://dlang.org/dstyle.html#phobos). [Additional Requirements for Phobos](https://dlang.org/dstyle.html#phobos)).
You can also use [dscanner](https://github.com/dlang-community/D-Scanner) to test the new code against the
most guidlines. The root of this repository contains
[dscanner.ini](https://github.com/caraus-ecms/tanya/blob/master/dscanner.ini), configuration file with settings for an
automatic style check. Just go to the top-level directory and issue (this assumes `dscanner` is installed in your
system):
```shell
dscanner --styleCheck source
```
## Questions and suggestions ## Questions and suggestions
* [Open an issue](https://issues.caraus.io/projects/tanya/issues) * [Open an issue](https://github.com/caraus-ecms/tanya/issues)
* [Send an email](mailto:info@caraus.de) * [Send an email](mailto:info@caraus.de)

View File

@ -27,6 +27,10 @@ Tanya consists of the following packages and (top-level) modules:
* `async`: Event loop (epoll, kqueue and IOCP). * `async`: Event loop (epoll, kqueue and IOCP).
* `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8 * `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8
string, Hash set. string, Hash set.
* `conv`: This module provides functions for converting between different
types.
* `encoding`: This package provides tools to work with text encodings.
* `exception`: Common exceptions and errors.
* `format`: Formatting and conversion functions. * `format`: Formatting and conversion functions.
* `math`: Arbitrary precision integer and a set of functions. * `math`: Arbitrary precision integer and a set of functions.
* `memory`: Tools for manual memory management (allocators, smart pointers). * `memory`: Tools for manual memory management (allocators, smart pointers).
@ -40,6 +44,7 @@ After finishing the new socket implementation will land in the `net` package and
`network` will be deprecated. `network` will be deprecated.
* `os`: Platform-independent interfaces to operating system functionality. * `os`: Platform-independent interfaces to operating system functionality.
* `range`: Generic functions and templates for D ranges. * `range`: Generic functions and templates for D ranges.
* `test`: Test suite for unittest-blocks.
* `typecons`: Templates that allow to build new types based on the available * `typecons`: Templates that allow to build new types based on the available
ones. ones.
@ -142,12 +147,11 @@ There are more containers in the `tanya.container` package.
### Supported compilers ### Supported compilers
| dmd | | DMD | GCC |
|:-------:| |:-------:|:--------------:|
| 2.076.0 | | 2.076.1 | *gdc-5* branch |
| 2.075.1 | | 2.075.1 | |
| 2.074.1 | | 2.074.1 | |
| 2.073.2 |
### Current status ### Current status

View File

@ -4,10 +4,10 @@ os: Visual Studio 2015
environment: environment:
matrix: matrix:
- DC: dmd - DC: dmd
DVersion: 2.076.0 DVersion: 2.076.1
arch: x64 arch: x64
- DC: dmd - DC: dmd
DVersion: 2.076.0 DVersion: 2.076.1
arch: x86 arch: x86
- DC: dmd - DC: dmd
DVersion: 2.075.1 DVersion: 2.075.1
@ -21,12 +21,6 @@ environment:
- DC: dmd - DC: dmd
DVersion: 2.074.1 DVersion: 2.074.1
arch: x86 arch: x86
- DC: dmd
DVersion: 2.073.2
arch: x64
- DC: dmd
DVersion: 2.073.2
arch: x86
skip_tags: true skip_tags: true

14
arch/build.ninja Normal file
View File

@ -0,0 +1,14 @@
rule gas
command = gcc -c $in -o $out
rule archive
command = ar rcs $out $in
build abs.o: gas x64/linux/math/abs.S
build log.o: gas x64/linux/math/log.S
build cmp.o: gas x64/linux/memory/cmp.S
build fill.o: gas x64/linux/memory/fill.S
build copy.o: gas x64/linux/memory/copy.S
build syscall.o: gas x64/linux/syscall.S
build tanya.a: archive syscall.o copy.o fill.o cmp.o log.o abs.o

View File

@ -0,0 +1,8 @@
.text
.globl thrd_current
.type thrd_current, @function
thrd_current:
mov %fs:0, %rax
ret

35
arch/x64/linux/math/abs.S Normal file
View File

@ -0,0 +1,35 @@
.text
// fabsf.
.globl _D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf
.type _D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf, @function
_D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf:
mov $0x7fffffff, %eax
movq %rax, %xmm1
andpd %xmm1, %xmm0
ret
// fabs.
.globl _D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd
.type _D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd, @function
_D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd:
mov $0x7fffffffffffffff, %rax
movq %rax, %xmm1
andpd %xmm1, %xmm0
ret
// fabsl.
.globl _D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe
.type _D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe, @function
// Load the parameter from the stack onto FP stack, execute 'fabs' instruction
// The result is returned in ST0.
_D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe:
fldt 0x8(%rsp)
fabs
ret

48
arch/x64/linux/math/log.S Normal file
View File

@ -0,0 +1,48 @@
.text
// logl.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNfeZe
.type _D5tanya4math8nbtheory2lnFNaNbNiNfeZe, @function
_D5tanya4math8nbtheory2lnFNaNbNiNfeZe:
fldln2 // Put lb(e) onto the FPU stack
fldt 8(%rsp) // Put the argument onto the FPU stack
fyl2x // %st1 * lb(%st0)
ret
// log.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNfdZd
.type _D5tanya4math8nbtheory2lnFNaNbNiNfdZd, @function
_D5tanya4math8nbtheory2lnFNaNbNiNfdZd:
movsd %xmm0, -8(%rsp) // Put the argument onto the stack
fldln2 // Put lb(e) onto the FPU stack
fldl -8(%rsp) // Put a double onto the FPU stack
fyl2x // %st1 * lb(%st0)
// The result is on the FPU stack, but returned in %xmm0
fstpl -8(%rsp)
movsd -8(%rsp), %xmm0
ret
// logf.
.globl _D5tanya4math8nbtheory2lnFNaNbNiNffZf
.type _D5tanya4math8nbtheory2lnFNaNbNiNffZf, @function
_D5tanya4math8nbtheory2lnFNaNbNiNffZf:
movss %xmm0, -4(%rsp) // Put the argument onto the stack
fldln2 // Put lb(e) onto the FPU stack
flds -4(%rsp) // Put a float onto the FPU stack
fyl2x // %st1 * lb(%st0)
// The result is on the FPU stack, but returned in %xmm0
fstps -4(%rsp)
movss -4(%rsp), %xmm0
ret

View File

@ -0,0 +1,67 @@
.text
/*
* cmpMemory.
*
* rdi - r1 length
* rsi - r1 data.
* rdx - r2 length.
* rcx - r2 data.
*/
.globl _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi
.type _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi, @function
_D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi:
// Compare the lengths
cmp %rdx, %rdi
jl less
jg greater
mov %rcx, %rdi
// Check if we're aligned
cmp $0x08, %rdx
jc aligned_1
test $0x07, %edi
jz aligned_8
naligned:
cmpsb
jl less
jg greater
dec %rdx
test $0x07, %edi
jnz naligned
aligned_8:
mov %rdx, %rcx
shr $0x03, %rcx
repe cmpsq
jl less
jg greater
and $0x07, %edx
jz equal
aligned_1: // Compare the remaining bytes
mov %rdx, %rcx
repe cmpsb
jl less
jg greater
equal:
xor %rax, %rax // Return 0
jmp end
greater:
mov $0x01, %rax
jmp end
less:
mov $-0x01, %rax
end:
ret

View File

@ -0,0 +1,67 @@
.text
/*
* copyMemory.
*
* rdi - source length
* rsi - source data.
* rdx - target length.
* rcx - target data.
*/
.globl _D5tanya6memory2op10copyMemoryFNaNbNixAvAvZv
.type _D5tanya6memory2op10copyMemoryFNaNbNixAvAvZv, @function
_D5tanya6memory2op10copyMemoryFNaNbNixAvAvZv:
mov %rdi, %rdx
mov %rcx, %rdi
cmp $0x08, %rdx
jc aligned_1
test $0x07, %edi
jz aligned_8
naligned:
movsb
dec %rdx
test $0x07, %edi
jnz naligned
aligned_8:
mov %rdx, %rcx
shr $0x03, %rcx
rep movsq
and $0x07, %edx
jz end
aligned_1:
// Write the remaining bytes
mov %rdx, %rcx
rep movsb
end:
ret
/*
* moveMemory.
*
* rdi - source length
* rsi - source data.
* rdx - target length.
* rcx - target data.
*/
.globl _D5tanya6memory2op10moveMemoryFNaNbNixAvAvZv
.type _D5tanya6memory2op10moveMemoryFNaNbNixAvAvZv, @function
_D5tanya6memory2op10moveMemoryFNaNbNixAvAvZv:
mov %rdi, %rdx
lea -1(%rdx, %rsi), %rsi
lea -1(%rdx, %rcx), %rdi
mov %rdx, %rcx
std // Set the direction flag
rep movsb
cld // Clear the direction flag
ret

View File

@ -0,0 +1,155 @@
.text
/*
* fillMemory.
*
* rdi - length.
* rsi - pointer.
* rdx - value filled with a byte.
*/
.globl _D5tanya6memory2op10fillMemoryFNaNbNiAvmZv
.type _D5tanya6memory2op10fillMemoryFNaNbNiAvmZv, @function
_D5tanya6memory2op10fillMemoryFNaNbNiAvmZv:
// Check for zero length
test %rdi, %rdi
jz end
mov %rdi, %rax
mov %rsi, %r8
movq %rdx, %xmm0
movlhps %xmm0, %xmm0
// Check if the pointer is aligned to a 16-byte boundary
and $-0x10, %r8
// Compute the number of misaligned bytes
mov %rsi, %r9
sub %r8, %r9
test %r9, %r9
jz aligned
// Get the number of bytes to be written until we are aligned
mov $0x10, %rcx
sub %r9, %rcx
mov %rsi, %r8
naligned:
mov %dl, (%r8) // Write a byte
// Advance the pointer. Decrease the total number of bytes
// and the misaligned ones
inc %r8
dec %rcx
dec %rax
// Checks if we are aligned
test %rcx, %rcx
jnz naligned
aligned:
// Checks if we're done writing bytes
test %rax, %rax
jz end
// Write 1 byte at a time
cmp $8, %rax
jl aligned_1
// Write 8 bytes at a time
cmp $16, %rax
jl aligned_8
// Write 16 bytes at a time
cmp $32, %rax
jl aligned_16
// Write 32 bytes at a time
cmp $64, %rax
jl aligned_32
aligned_64:
movdqa %xmm0, (%r8)
movdqa %xmm0, 16(%r8)
movdqa %xmm0, 32(%r8)
movdqa %xmm0, 48(%r8)
add $64, %r8
sub $64, %rax
cmp $64, %rax
jge aligned_64
// Checks if we're done writing bytes
test %rax, %rax
jz end
// Write 1 byte at a time
cmp $8, %rax
jl aligned_1
// Write 8 bytes at a time
cmp $16, %rax
jl aligned_8
// Write 16 bytes at a time
cmp $32, %rax
jl aligned_16
aligned_32:
movdqa %xmm0, (%r8)
movdqa %xmm0, 16(%r8)
add $32, %r8
sub $32, %rax
// Checks if we're done writing bytes
test %rax, %rax
jz end
// Write 1 byte at a time
cmp $8, %rax
jl aligned_1
// Write 8 bytes at a time
cmp $16, %rax
jl aligned_8
aligned_16:
movdqa %xmm0, (%r8)
add $16, %r8
sub $16, %rax
// Checks if we're done writing bytes
test %rax, %rax
jz end
// Write 1 byte at a time
cmp $8, %rax
jl aligned_1
aligned_8:
mov %rdx, (%r8)
add $8, %r8
sub $8, %rax
// Checks if we're done writing bytes
test %rax, %rax
jz end
aligned_1:
mov %dl, (%r8)
inc %r8
dec %rax
test %rax, %rax
jnz aligned_1
end:
ret

65
arch/x64/linux/syscall.S Normal file
View File

@ -0,0 +1,65 @@
/*
The kernel uses the following registers:
%rdi, %rsi, %rdx, %r8, %r9, %r10
The number of the syscall is passed in %rax.
A syscall clobbers:
%rax, %rcx, %r11
The returned value is placed in %rax.
*/
.text
.globl syscall1
.type syscall1, @function
syscall1:
movq %rsi, %rax // Syscall number.
syscall
ret
.globl syscall2
.type syscall2, @function
syscall2:
// Store registers.
movq %rdi, %r8
movq %rdx, %rax // Syscall number.
// Syscall arguments.
movq %rsi, %rdi
movq %r8, %rsi
syscall
// Restore registers.
movq %rdi, %rsi
movq %r8, %rdi
ret
.globl syscall3
.type syscall3, @function
syscall3:
// Store registers.
movq %rdi, %r8
movq %rcx, %rax // Syscall number.
// Syscall arguments.
movq %rdx, %rdi
movq %r8, %rdx
syscall
// Restore registers.
movq %r8, %rdi
ret

View File

@ -74,7 +74,7 @@ lambda_return_check="skip-unittest"
; Check for auto function without return statement ; Check for auto function without return statement
auto_function_check="skip-unittest" auto_function_check="skip-unittest"
; Check for sortedness of imports ; Check for sortedness of imports
imports_sortedness="disabled" imports_sortedness="skip-unittest"
; Check for explicitly annotated unittests ; Check for explicitly annotated unittests
explicitly_annotated_unittests="disabled" explicitly_annotated_unittests="disabled"
; Check for useless usage of the final attribute ; Check for useless usage of the final attribute

View File

@ -18,7 +18,10 @@
{ {
"name": "native", "name": "native",
"targetType": "library", "targetType": "library",
"platforms": ["linux-x86_64"] "platforms": ["linux-x86_64-gdc"],
"preBuildCommands": ["ninja -C arch"],
"lflags": ["arch/tanya.a"],
"versions": ["TanyaNative"]
} }
] ]
} }

View File

@ -19,20 +19,20 @@ version (D_Ddoc)
} }
else version (linux): else version (linux):
import core.stdc.errno;
public import core.sys.linux.epoll; public import core.sys.linux.epoll;
import tanya.async.protocol; import core.sys.posix.unistd;
import core.time;
import std.algorithm.comparison;
import tanya.async.event.selector; import tanya.async.event.selector;
import tanya.async.loop; import tanya.async.loop;
import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool; import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
import core.stdc.errno;
import core.sys.posix.unistd;
import core.time;
import std.algorithm.comparison;
extern (C) nothrow @nogc extern (C) nothrow @nogc
{ {

View File

@ -19,19 +19,17 @@ version (D_Ddoc)
} }
else version (Windows): else version (Windows):
import tanya.container.buffer; import core.sys.windows.mswsock;
import core.sys.windows.winsock2;
import tanya.async.loop; import tanya.async.loop;
import tanya.async.protocol; import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.buffer;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool; import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;
import core.sys.windows.basetyps; import tanya.sys.windows.winbase;
import core.sys.windows.mswsock;
import core.sys.windows.winbase;
import core.sys.windows.windef;
import core.sys.windows.winsock2;
/** /**
* Transport for stream sockets. * Transport for stream sockets.
@ -185,7 +183,7 @@ final class IOCPLoop : Loop
{ {
super(); super();
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, null, 0, 0);
if (!completionPort) if (!completionPort)
{ {
throw make!BadLoopException(defaultAllocator, throw make!BadLoopException(defaultAllocator,
@ -215,7 +213,7 @@ final class IOCPLoop : Loop
if (CreateIoCompletionPort(cast(HANDLE) socket.handle, if (CreateIoCompletionPort(cast(HANDLE) socket.handle,
completionPort, completionPort,
cast(ULONG_PTR) (cast(void*) watcher), cast(size_t) (cast(void*) watcher),
0) !is completionPort) 0) !is completionPort)
{ {
return false; return false;
@ -241,7 +239,7 @@ final class IOCPLoop : Loop
if (CreateIoCompletionPort(cast(HANDLE) transport.socket.handle, if (CreateIoCompletionPort(cast(HANDLE) transport.socket.handle,
completionPort, completionPort,
cast(ULONG_PTR) (cast(void*) watcher), cast(size_t) (cast(void*) watcher),
0) !is completionPort) 0) !is completionPort)
{ {
return false; return false;
@ -286,8 +284,8 @@ final class IOCPLoop : Loop
override protected void poll() @nogc override protected void poll() @nogc
{ {
DWORD lpNumberOfBytes; DWORD lpNumberOfBytes;
ULONG_PTR key; size_t key;
LPOVERLAPPED overlap; OVERLAPPED* overlap;
immutable timeout = cast(immutable int) blockTime.total!"msecs"; immutable timeout = cast(immutable int) blockTime.total!"msecs";
auto result = GetQueuedCompletionStatus(completionPort, auto result = GetQueuedCompletionStatus(completionPort,
@ -295,7 +293,7 @@ final class IOCPLoop : Loop
&key, &key,
&overlap, &overlap,
timeout); timeout);
if (result == FALSE && overlap == NULL) if (result == FALSE && overlap is null)
{ {
return; // Timeout return; // Timeout
} }

View File

@ -23,8 +23,8 @@ import tanya.async.loop;
import tanya.async.protocol; import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.buffer;
import tanya.container.array; import tanya.container.array;
import tanya.container.buffer;
import tanya.memory; import tanya.memory;
import tanya.memory.mmappool; import tanya.memory.mmappool;
import tanya.network.socket; import tanya.network.socket;

View File

@ -37,8 +37,7 @@ else version (D_Ddoc)
version (WindowsDoc): version (WindowsDoc):
import core.sys.windows.winbase; import tanya.sys.windows.winbase;
import core.sys.windows.windef;
/** /**
* Provides an extendable representation of a Win32 $(D_PSYMBOL OVERLAPPED) * Provides an extendable representation of a Win32 $(D_PSYMBOL OVERLAPPED)

View File

@ -18,8 +18,8 @@
*/ */
module tanya.async.protocol; module tanya.async.protocol;
import tanya.network.socket;
import tanya.async.transport; import tanya.async.transport;
import tanya.network.socket;
/** /**
* Common protocol interface. * Common protocol interface.

View File

@ -14,8 +14,8 @@
*/ */
module tanya.async.watcher; module tanya.async.watcher;
import std.functional;
import std.exception; import std.exception;
import std.functional;
import tanya.async.loop; import tanya.async.loop;
import tanya.async.protocol; import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;

View File

@ -15,15 +15,14 @@
module tanya.container.array; module tanya.container.array;
import core.checkedint; import core.checkedint;
import core.exception;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation;
import std.conv;
import std.range.primitives;
import std.meta; import std.meta;
import tanya.exception;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.primitive;
/** /**
* Random-access range for the $(D_PSYMBOL Array). * Random-access range for the $(D_PSYMBOL Array).
@ -177,7 +176,7 @@ struct Array(T)
/// The range types for $(D_PSYMBOL Array). /// The range types for $(D_PSYMBOL Array).
alias Range = .Range!Array; alias Range = .Range!Array;
/// Ditto. /// ditto
alias ConstRange = .Range!(const Array); alias ConstRange = .Range!(const Array);
private size_t length_; private size_t length_;
@ -245,7 +244,7 @@ struct Array(T)
insertBack(init[]); insertBack(init[]);
} }
/// Ditto. /// ditto
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
if (is(R == Array)) if (is(R == Array))
{ {
@ -313,14 +312,14 @@ struct Array(T)
length_ = len; length_ = len;
} }
/// Ditto. /// ditto
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
this(allocator); this(allocator);
length = len; length = len;
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -416,7 +415,7 @@ struct Array(T)
return length_; return length_;
} }
/// Ditto. /// ditto
size_t opDollar() const size_t opDollar() const
{ {
return length; return length;
@ -501,7 +500,7 @@ struct Array(T)
buf = allocator.allocate(byteSize); buf = allocator.allocate(byteSize);
if (buf is null) if (buf is null)
{ {
onOutOfMemoryErrorNoGC(); onOutOfMemoryError();
} }
scope (failure) scope (failure)
{ {
@ -704,17 +703,20 @@ struct Array(T)
return 1; return 1;
} }
/// Ditto. /// ditto
size_t insertBack(R)(ref R el) @trusted size_t insertBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
reserve(this.length_ + 1); this.length = this.length + 1;
emplace(this.data + this.length_, el); scope (failure)
++this.length_; {
this.length = this.length - 1;
}
opIndex(this.length - 1) = el;
return 1; return 1;
} }
/// Ditto. /// ditto
size_t insertBack(R)(R el) size_t insertBack(R)(R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -732,13 +734,13 @@ struct Array(T)
return retLength; return retLength;
} }
/// Ditto. /// ditto
size_t insertBack(size_t R)(T[R] el) size_t insertBack(size_t R)(T[R] el)
{ {
return insertBack!(T[])(el[]); return insertBack!(T[])(el[]);
} }
/// Ditto. /// ditto
alias insert = insertBack; alias insert = insertBack;
/// ///
@ -813,7 +815,7 @@ struct Array(T)
return inserted; return inserted;
} }
/// Ditto. /// ditto
size_t insertAfter(size_t R)(Range r, T[R] el) size_t insertAfter(size_t R)(Range r, T[R] el)
in in
{ {
@ -826,7 +828,7 @@ struct Array(T)
return insertAfter!(T[])(r, el[]); return insertAfter!(T[])(r, el[]);
} }
/// Ditto. /// ditto
size_t insertAfter(R)(Range r, auto ref R el) size_t insertAfter(R)(Range r, auto ref R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
@ -853,7 +855,7 @@ struct Array(T)
return 1; return 1;
} }
/// Ditto. /// ditto
size_t insertBefore(R)(Range r, R el) size_t insertBefore(R)(Range r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -869,7 +871,7 @@ struct Array(T)
return insertAfter(Range(this, this.data, r.begin), el); return insertAfter(Range(this, this.data, r.begin), el);
} }
/// Ditto. /// ditto
size_t insertBefore(size_t R)(Range r, T[R] el) size_t insertBefore(size_t R)(Range r, T[R] el)
in in
{ {
@ -882,7 +884,7 @@ struct Array(T)
return insertBefore!(T[])(r, el[]); return insertBefore!(T[])(r, el[]);
} }
/// Ditto. /// ditto
size_t insertBefore(R)(Range r, auto ref R el) size_t insertBefore(R)(Range r, auto ref R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
@ -998,7 +1000,7 @@ struct Array(T)
return opIndex(pos) = value; return opIndex(pos) = value;
} }
/// Ditto. /// ditto
Range opIndexAssign(E : T)(auto ref E value) Range opIndexAssign(E : T)(auto ref E value)
{ {
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
@ -1028,7 +1030,7 @@ struct Array(T)
return opSliceAssign!R(value, 0, length); return opSliceAssign!R(value, 0, length);
} }
/// Ditto. /// ditto
Range opIndexAssign(Range value) Range opIndexAssign(Range value)
{ {
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
@ -1077,7 +1079,7 @@ struct Array(T)
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
} }
/// Ditto. /// ditto
ConstRange opIndex() const @trusted ConstRange opIndex() const @trusted
{ {
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
@ -1110,13 +1112,13 @@ struct Array(T)
return equal(this.data[0 .. length], that.data[0 .. that.length]); return equal(this.data[0 .. length], that.data[0 .. that.length]);
} }
/// Ditto. /// ditto
bool opEquals()(auto ref const typeof(this) that) const @trusted bool opEquals()(auto ref const typeof(this) that) const @trusted
{ {
return equal(this.data[0 .. length], that.data[0 .. that.length]); return equal(this.data[0 .. length], that.data[0 .. that.length]);
} }
/// Ditto. /// ditto
bool opEquals(Range that) bool opEquals(Range that)
{ {
return equal(opIndex(), that); return equal(opIndex(), that);
@ -1233,7 +1235,7 @@ struct Array(T)
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
/// Ditto. /// ditto
ConstRange opSlice(const size_t i, const size_t j) const @trusted ConstRange opSlice(const size_t i, const size_t j) const @trusted
in in
{ {
@ -1317,7 +1319,7 @@ struct Array(T)
return opSlice(i, j); return opSlice(i, j);
} }
/// Ditto. /// ditto
Range opSliceAssign(R : T)(auto ref R value, const size_t i, const size_t j) Range opSliceAssign(R : T)(auto ref R value, const size_t i, const size_t j)
@trusted @trusted
in in
@ -1331,7 +1333,7 @@ struct Array(T)
return opSlice(i, j); return opSlice(i, j);
} }
/// Ditto. /// ditto
Range opSliceAssign(Range value, const size_t i, const size_t j) @trusted Range opSliceAssign(Range value, const size_t i, const size_t j) @trusted
in in
{ {
@ -1416,7 +1418,7 @@ struct Array(T)
return this = that[]; return this = that[];
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(R)(R that) @trusted ref typeof(this) opAssign(R)(R that) @trusted
if (is(R == Array)) if (is(R == Array))
{ {

View File

@ -100,7 +100,7 @@ struct ReadBuffer(T = ubyte)
buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof); buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof);
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -143,7 +143,7 @@ struct ReadBuffer(T = ubyte)
return length_ - start; return length_ - start;
} }
/// Ditto. /// ditto
alias opDollar = length; alias opDollar = length;
/** /**
@ -395,7 +395,7 @@ struct WriteBuffer(T = ubyte)
} }
} }
/// Ditto. /// ditto
alias opDollar = length; alias opDollar = length;
/// ///

View File

@ -17,10 +17,11 @@ module tanya.container.list;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation;
import std.algorithm.searching; import std.algorithm.searching;
import std.range.primitives;
import tanya.container.entry; import tanya.container.entry;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.range.array;
import tanya.range.primitive;
/** /**
* Forward range for the $(D_PSYMBOL SList). * Forward range for the $(D_PSYMBOL SList).
@ -99,7 +100,7 @@ struct SList(T)
/// The range types for $(D_PSYMBOL SList). /// The range types for $(D_PSYMBOL SList).
alias Range = SRange!SList; alias Range = SRange!SList;
/// Ditto. /// ditto
alias ConstRange = SRange!(const SList); alias ConstRange = SRange!(const SList);
private alias Entry = SEntry!T; private alias Entry = SEntry!T;
@ -183,7 +184,7 @@ struct SList(T)
assert(l.empty); assert(l.empty);
} }
/// Ditto. /// ditto
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
this(len, T.init, allocator); this(len, T.init, allocator);
@ -197,7 +198,7 @@ struct SList(T)
assert(l.front == 0); assert(l.front == 0);
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -231,7 +232,7 @@ struct SList(T)
this(init[], allocator); this(init[], allocator);
} }
/// Ditto. /// ditto
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
if (is(R == SList)) if (is(R == SList))
{ {
@ -355,7 +356,7 @@ struct SList(T)
return moveEntry(this.head, el); return moveEntry(this.head, el);
} }
/// Ditto. /// ditto
size_t insertFront(R)(ref R el) @trusted size_t insertFront(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
@ -377,7 +378,7 @@ struct SList(T)
assert(l.front == 8); assert(l.front == 8);
} }
/// Ditto. /// ditto
size_t insertFront(R)(R el) @trusted size_t insertFront(R)(R el) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -407,13 +408,13 @@ struct SList(T)
return retLength; return retLength;
} }
/// Ditto. /// ditto
size_t insertFront(size_t R)(T[R] el) size_t insertFront(size_t R)(T[R] el)
{ {
return insertFront!(T[])(el[]); return insertFront!(T[])(el[]);
} }
/// Ditto. /// ditto
alias insert = insertFront; alias insert = insertFront;
/// ///
@ -479,7 +480,7 @@ struct SList(T)
assert(l1 == l2); assert(l1 == l2);
} }
/// Ditto. /// ditto
size_t insertBefore(R)(Range r, R el) size_t insertBefore(R)(Range r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -511,7 +512,7 @@ struct SList(T)
assert(l1 == l2); assert(l1 == l2);
} }
/// Ditto. /// ditto
size_t insertBefore(Range r, ref T el) @trusted size_t insertBefore(Range r, ref T el) @trusted
in in
{ {
@ -745,7 +746,7 @@ struct SList(T)
return typeof(return)(this.head); return typeof(return)(this.head);
} }
/// Ditto. /// ditto
ConstRange opIndex() const ConstRange opIndex() const
{ {
return typeof(return)(this.head); return typeof(return)(this.head);
@ -772,7 +773,7 @@ struct SList(T)
return this = that[]; return this = that[];
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(R)(R that) ref typeof(this) opAssign(R)(R that)
if (is(R == SList)) if (is(R == SList))
{ {
@ -1018,7 +1019,7 @@ struct DList(T)
/// The range types for $(D_PSYMBOL DList). /// The range types for $(D_PSYMBOL DList).
alias Range = DRange!DList; alias Range = DRange!DList;
/// Ditto. /// ditto
alias ConstRange = DRange!(const DList); alias ConstRange = DRange!(const DList);
private alias Entry = DEntry!T; private alias Entry = DEntry!T;
@ -1113,7 +1114,7 @@ struct DList(T)
assert(l.empty); assert(l.empty);
} }
/// Ditto. /// ditto
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
this(len, T.init, allocator); this(len, T.init, allocator);
@ -1127,7 +1128,7 @@ struct DList(T)
assert(l.front == 0); assert(l.front == 0);
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -1161,7 +1162,7 @@ struct DList(T)
this(init[], allocator); this(init[], allocator);
} }
/// Ditto. /// ditto
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
if (is(R == DList)) if (is(R == DList))
{ {
@ -1352,7 +1353,7 @@ struct DList(T)
return moveFront(this.head, el); return moveFront(this.head, el);
} }
/// Ditto. /// ditto
size_t insertFront(R)(ref R el) @trusted size_t insertFront(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
@ -1384,7 +1385,7 @@ struct DList(T)
assert(l.back == 5); assert(l.back == 5);
} }
/// Ditto. /// ditto
size_t insertFront(R)(R el) size_t insertFront(R)(R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -1412,7 +1413,7 @@ struct DList(T)
assert(l1.head is l1.head.next.prev); assert(l1.head is l1.head.next.prev);
} }
/// Ditto. /// ditto
size_t insertFront(size_t R)(T[R] el) size_t insertFront(size_t R)(T[R] el)
{ {
return insertFront!(T[])(el[]); return insertFront!(T[])(el[]);
@ -1478,7 +1479,7 @@ struct DList(T)
return moveBack(this.tail, el); return moveBack(this.tail, el);
} }
/// Ditto. /// ditto
size_t insertBack(R)(ref R el) @trusted size_t insertBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
@ -1510,7 +1511,7 @@ struct DList(T)
assert(l.back == value); assert(l.back == value);
} }
/// Ditto. /// ditto
size_t insertBack(R)(R el) @trusted size_t insertBack(R)(R el) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -1535,7 +1536,7 @@ struct DList(T)
return inserted; return inserted;
} }
/// Ditto. /// ditto
size_t insertBack(size_t R)(T[R] el) size_t insertBack(size_t R)(T[R] el)
{ {
return insertBack!(T[])(el[]); return insertBack!(T[])(el[]);
@ -1560,7 +1561,7 @@ struct DList(T)
assert(l2.back == 9); assert(l2.back == 9);
} }
/// Ditto. /// ditto
alias insert = insertBack; alias insert = insertBack;
version (assert) version (assert)
@ -1607,7 +1608,7 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
/// Ditto. /// ditto
size_t insertBefore(Range r, ref T el) @trusted size_t insertBefore(Range r, ref T el) @trusted
in in
{ {
@ -1642,7 +1643,7 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
/// Ditto. /// ditto
size_t insertBefore(R)(Range r, R el) size_t insertBefore(R)(Range r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -1733,7 +1734,7 @@ struct DList(T)
assert(l.length == 1); assert(l.length == 1);
} }
/// Ditto. /// ditto
size_t insertAfter(Range r, ref T el) @trusted size_t insertAfter(Range r, ref T el) @trusted
in in
{ {
@ -1768,7 +1769,7 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
/// Ditto. /// ditto
size_t insertAfter(R)(Range r, R el) size_t insertAfter(R)(Range r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
@ -1924,7 +1925,7 @@ struct DList(T)
assert(l.empty); assert(l.empty);
} }
/// Ditto. /// ditto
void removeBack() void removeBack()
in in
{ {
@ -1997,7 +1998,7 @@ struct DList(T)
assert(l.removeFront(3) == 0); assert(l.removeFront(3) == 0);
} }
/// Ditto. /// ditto
size_t removeBack(const size_t howMany) size_t removeBack(const size_t howMany)
out (removed) out (removed)
{ {
@ -2110,7 +2111,7 @@ struct DList(T)
return typeof(return)(this.head, this.tail); return typeof(return)(this.head, this.tail);
} }
/// Ditto. /// ditto
ConstRange opIndex() const ConstRange opIndex() const
{ {
return typeof(return)(this.head, this.tail); return typeof(return)(this.head, this.tail);
@ -2137,7 +2138,7 @@ struct DList(T)
return this = that[]; return this = that[];
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(R)(R that) ref typeof(this) opAssign(R)(R that)
if (is(R == DList)) if (is(R == DList))
{ {

View File

@ -16,10 +16,10 @@ module tanya.container;
public import tanya.container.array; public import tanya.container.array;
public import tanya.container.buffer; public import tanya.container.buffer;
public import tanya.container.set;
public import tanya.container.list; public import tanya.container.list;
public import tanya.container.string;
public import tanya.container.queue; public import tanya.container.queue;
public import tanya.container.set;
public import tanya.container.string;
/** /**
* Thrown if $(D_PSYMBOL Set) cannot insert a new element because the container * Thrown if $(D_PSYMBOL Set) cannot insert a new element because the container

View File

@ -14,9 +14,9 @@
*/ */
module tanya.container.queue; module tanya.container.queue;
import core.exception;
import std.algorithm.mutation; import std.algorithm.mutation;
import tanya.container.entry; import tanya.container.entry;
import tanya.exception;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
@ -115,7 +115,7 @@ struct Queue(T)
enqueueEntry(temp); enqueueEntry(temp);
} }
/// Ditto. /// ditto
void enqueue(T x) void enqueue(T x)
{ {
auto temp = allocateEntry(); auto temp = allocateEntry();
@ -201,7 +201,7 @@ struct Queue(T)
{ {
int result; int result;
for (size_t i = 0; !empty; ++i) for (size_t i; !empty; ++i)
{ {
auto e = dequeue(); auto e = dequeue();
if ((result = dg(i, e)) != 0) if ((result = dg(i, e)) != 0)
@ -212,7 +212,7 @@ struct Queue(T)
return result; return result;
} }
/// Ditto. /// ditto
int opApply(scope int delegate(ref T) @nogc dg) int opApply(scope int delegate(ref T) @nogc dg)
{ {
int result; int result;

View File

@ -156,7 +156,7 @@ struct Set(T)
/// The range types for $(D_PSYMBOL Set). /// The range types for $(D_PSYMBOL Set).
alias Range = .Range!T; alias Range = .Range!T;
/// Ditto. /// ditto
alias ConstRange = .Range!(const T); alias ConstRange = .Range!(const T);
invariant invariant
@ -186,7 +186,7 @@ struct Set(T)
rehash(n); rehash(n);
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -232,7 +232,7 @@ struct Set(T)
this.data = typeof(this.data)(init.data, allocator); this.data = typeof(this.data)(init.data, allocator);
} }
/// Ditto. /// ditto
this(S)(S init, shared Allocator allocator = defaultAllocator) this(S)(S init, shared Allocator allocator = defaultAllocator)
if (is(S == Set)) if (is(S == Set))
in in
@ -266,7 +266,7 @@ struct Set(T)
return this; return this;
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(S)(S that) @trusted ref typeof(this) opAssign(S)(S that) @trusted
if (is(S == Set)) if (is(S == Set))
{ {
@ -437,7 +437,7 @@ struct Set(T)
InsertStatus status = insertInUnusedBucket(value); InsertStatus status = insertInUnusedBucket(value);
for (; !status; status = insertInUnusedBucket(value)) for (; !status; status = insertInUnusedBucket(value))
{ {
if ((this.primes.length - 1) == this.lengthIndex) if (this.primes.length == (this.lengthIndex + 1))
{ {
throw make!HashContainerFullException(defaultAllocator, throw make!HashContainerFullException(defaultAllocator,
"Set is full"); "Set is full");
@ -614,7 +614,7 @@ struct Set(T)
return typeof(return)(this.data[]); return typeof(return)(this.data[]);
} }
/// Ditto. /// ditto
ConstRange opIndex() const ConstRange opIndex() const
{ {
return typeof(return)(this.data[]); return typeof(return)(this.data[]);
@ -702,7 +702,7 @@ private @nogc unittest
// Static checks. // Static checks.
private unittest private unittest
{ {
import std.range.primitives; import tanya.range.primitive;
static assert(isBidirectionalRange!(Set!int.ConstRange)); static assert(isBidirectionalRange!(Set!int.ConstRange));
static assert(isBidirectionalRange!(Set!int.Range)); static assert(isBidirectionalRange!(Set!int.Range));

View File

@ -26,16 +26,20 @@
*/ */
module tanya.container.string; module tanya.container.string;
import core.exception;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation;
import std.algorithm.searching; import std.algorithm.searching;
import std.range : isInfinite, isInputRange, ElementEncodingType, hasLength, static import std.range;
popFrontN, empty;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.array; import tanya.range.array;
import tanya.range.primitive;
version (unittest)
{
import tanya.test.assertion;
}
/** /**
* Thrown on encoding errors. * Thrown on encoding errors.
@ -292,21 +296,21 @@ if (is(Unqual!E == char))
body body
{ {
ubyte units; ubyte units;
if ((*begin & 0x80) == 0) if ((*begin & 0xf0) == 0xf0)
{ {
units = 1; units = 4;
}
else if ((*begin & 0xc0) == 0xc0)
{
units = 2;
} }
else if ((*begin & 0xe0) == 0xe0) else if ((*begin & 0xe0) == 0xe0)
{ {
units = 3; units = 3;
} }
else if ((*begin & 0xf0) == 0xf0) else if ((*begin & 0xc0) == 0xc0)
{ {
units = 4; units = 2;
}
else if ((*begin & 0x80) == 0)
{
units = 1;
} }
if (units == 0 || this.begin + units > this.end) if (units == 0 || this.begin + units > this.end)
{ {
@ -355,21 +359,21 @@ struct String
this(S)(const S str, shared Allocator allocator = defaultAllocator) this(S)(const S str, shared Allocator allocator = defaultAllocator)
if (!isInfinite!S if (!isInfinite!S
&& isInputRange!S && isInputRange!S
&& isSomeChar!(ElementEncodingType!S)) && isSomeChar!(ElementType!S))
{ {
this(allocator); this(allocator);
insertBack(str); insertBack(str);
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("\u10437"w); auto s = String("\u10437"w);
assert(s == "\u10437"); assert(s == "\u10437");
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Отказаться от вина - в этом страшная вина."d); auto s = String("Отказаться от вина - в этом страшная вина."d);
assert(s == "Отказаться от вина - в этом страшная вина."); assert(s == "Отказаться от вина - в этом страшная вина.");
@ -393,8 +397,7 @@ struct String
* *
* Precondition: $(D_INLINECODE allocator is null). * Precondition: $(D_INLINECODE allocator is null).
*/ */
this(S)(S init, shared Allocator allocator = defaultAllocator) this(S)(S init, shared Allocator allocator = defaultAllocator) @trusted
nothrow @trusted @nogc
if (is(S == String)) if (is(S == String))
{ {
this(allocator); this(allocator);
@ -417,9 +420,8 @@ struct String
} }
} }
/// Ditto. /// ditto
this(S)(ref S init, shared Allocator allocator = defaultAllocator) this(S)(ref S init, shared Allocator allocator = defaultAllocator) @trusted
nothrow @trusted @nogc
if (is(Unqual!S == String)) if (is(Unqual!S == String))
{ {
this(allocator); this(allocator);
@ -428,8 +430,8 @@ struct String
this.length_ = init.length; this.length_ = init.length;
} }
/// Ditto. /// ditto
this(shared Allocator allocator) pure nothrow @safe @nogc this(shared Allocator allocator) @nogc nothrow pure @safe
in in
{ {
assert(allocator !is null); assert(allocator !is null);
@ -479,7 +481,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
{ {
auto s = String(1, 'О'); auto s = String(1, 'О');
@ -495,22 +497,30 @@ struct String
} }
} }
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String(0, 'K'); auto s = String(0, 'K');
assert(s.length == 0); assert(s.length == 0);
} }
this(this) @nogc nothrow pure @trusted
{
auto buf = this.data[0 .. this.length_];
this.length_ = capacity_ = 0;
this.data = null;
insertBack(buf);
}
/** /**
* Destroys the string. * Destroys the string.
*/ */
~this() nothrow @trusted @nogc ~this() @nogc nothrow pure @trusted
{ {
allocator.resize(this.data[0 .. this.capacity_], 0); allocator.resize(this.data[0 .. this.capacity_], 0);
} }
private void write4Bytes(ref const dchar src) private void write4Bytes(ref const dchar src)
pure nothrow @trusted @nogc @nogc nothrow pure @trusted
in in
{ {
assert(capacity - length >= 4); assert(capacity - length >= 4);
@ -571,7 +581,7 @@ struct String
* *
* Throws: $(D_PSYMBOL UTFException). * Throws: $(D_PSYMBOL UTFException).
*/ */
size_t insertBack(const char chr) @trusted @nogc size_t insertBack(const char chr) @nogc pure @trusted
{ {
if ((chr & 0x80) != 0) if ((chr & 0x80) != 0)
{ {
@ -585,8 +595,8 @@ struct String
return 1; return 1;
} }
/// Ditto. /// ditto
size_t insertBack(const wchar chr) @trusted @nogc size_t insertBack(const wchar chr) @nogc pure @trusted
{ {
reserve(length + 3); reserve(length + 3);
@ -599,29 +609,14 @@ struct String
} }
// Allocates enough space for 3-byte character. // Allocates enough space for 3-byte character.
private @safe @nogc unittest @nogc pure @safe unittest
{ {
String s; String s;
s.insertBack('\u8100'); s.insertBack('\u8100');
} }
private @safe @nogc unittest /// ditto
{ size_t insertBack(const dchar chr) @nogc pure @trusted
UTFException exception;
try
{
auto s = String(1, cast(wchar) 0xd900);
}
catch (UTFException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
/// Ditto.
size_t insertBack(const dchar chr) @trusted @nogc
{ {
reserve(length + dchar.sizeof); reserve(length + dchar.sizeof);
@ -641,19 +636,10 @@ struct String
} }
} }
private @safe @nogc unittest @nogc pure @safe unittest
{ {
UTFException exception; assertThrown!UTFException(() => String(1, cast(dchar) 0xd900));
try assertThrown!UTFException(() => String(1, cast(wchar) 0xd900));
{
auto s = String(1, cast(dchar) 0xd900);
}
catch (UTFException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
} }
/** /**
@ -670,7 +656,7 @@ struct String
size_t insertBack(R)(R str) @trusted size_t insertBack(R)(R str) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& is(Unqual!(ElementEncodingType!R) == char)) && is(Unqual!(ElementType!R) == char))
{ {
size_t size; size_t size;
static if (hasLength!R || isNarrowString!R) static if (hasLength!R || isNarrowString!R)
@ -730,11 +716,11 @@ struct String
} }
} }
/// Ditto. /// ditto
size_t insertBack(R)(R str) @trusted size_t insertBack(R)(R str) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& is(Unqual!(ElementEncodingType!R) == wchar)) && is(Unqual!(ElementType!R) == wchar))
{ {
static if (hasLength!R || isNarrowString!R) static if (hasLength!R || isNarrowString!R)
{ {
@ -771,7 +757,7 @@ struct String
} }
dchar d = (range[0] - 0xd800) | ((range[1] - 0xdc00) >> 10); dchar d = (range[0] - 0xd800) | ((range[1] - 0xdc00) >> 10);
range.popFrontN(2); std.range.popFrontN(range, 2);
} }
else else
{ {
@ -796,11 +782,11 @@ struct String
return this.length_ - oldLength; return this.length_ - oldLength;
} }
/// Ditto. /// ditto
size_t insertBack(R)(R str) @trusted size_t insertBack(R)(R str) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& is(Unqual!(ElementEncodingType!R) == dchar)) && is(Unqual!(ElementType!R) == dchar))
{ {
static if (hasLength!R || isSomeString!R) static if (hasLength!R || isSomeString!R)
{ {
@ -815,7 +801,7 @@ struct String
return insertedLength; return insertedLength;
} }
/// Ditto. /// ditto
alias insert = insertBack; alias insert = insertBack;
/** /**
@ -828,7 +814,7 @@ struct String
* Params: * Params:
* size = Desired size in bytes. * size = Desired size in bytes.
*/ */
void reserve(const size_t size) nothrow @trusted @nogc void reserve(const size_t size) @nogc nothrow pure @trusted
{ {
if (this.capacity_ >= size) if (this.capacity_ >= size)
{ {
@ -840,7 +826,7 @@ struct String
} }
/// ///
@nogc @safe unittest @nogc pure @safe unittest
{ {
String s; String s;
assert(s.capacity == 0); assert(s.capacity == 0);
@ -864,7 +850,7 @@ struct String
* Params: * Params:
* size = Desired size. * size = Desired size.
*/ */
void shrink(const size_t size) nothrow @trusted @nogc void shrink(const size_t size) @nogc nothrow pure @trusted
{ {
if (this.capacity_ <= size) if (this.capacity_ <= size)
{ {
@ -881,7 +867,7 @@ struct String
} }
/// ///
@nogc @safe unittest @nogc pure @safe unittest
{ {
auto s = String("Die Alten lasen laut."); auto s = String("Die Alten lasen laut.");
assert(s.capacity == 21); assert(s.capacity == 21);
@ -900,13 +886,13 @@ struct String
/** /**
* Returns: String capacity in bytes. * Returns: String capacity in bytes.
*/ */
@property size_t capacity() const pure nothrow @safe @nogc @property size_t capacity() const @nogc nothrow pure @safe
{ {
return this.capacity_; return this.capacity_;
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("In allem Schreiben ist Schamlosigkeit."); auto s = String("In allem Schreiben ist Schamlosigkeit.");
assert(s.capacity == 38); assert(s.capacity == 38);
@ -928,7 +914,7 @@ struct String
*/ */
ByCodeUnit!char opSliceAssign(R)(ByCodeUnit!R value, ByCodeUnit!char opSliceAssign(R)(ByCodeUnit!R value,
const size_t i, const size_t i,
const size_t j) @trusted const size_t j)
if (is(Unqual!R == char)) if (is(Unqual!R == char))
in in
{ {
@ -943,11 +929,11 @@ struct String
return target; return target;
} }
/// Ditto. /// ditto
ByCodeUnit!char opSliceAssign(const char[] value, ByCodeUnit!char opSliceAssign(const char[] value,
const size_t i, const size_t i,
const size_t j) const size_t j)
pure nothrow @trusted @nogc @nogc nothrow pure @trusted
in in
{ {
assert(i <= j); assert(i <= j);
@ -959,11 +945,11 @@ struct String
return opSlice(i, j); return opSlice(i, j);
} }
/// Ditto. /// ditto
ByCodeUnit!char opSliceAssign(const char value, ByCodeUnit!char opSliceAssign(const char value,
const size_t i, const size_t i,
const size_t j) const size_t j)
pure nothrow @trusted @nogc @nogc nothrow pure @trusted
in in
{ {
assert(i <= j); assert(i <= j);
@ -985,13 +971,13 @@ struct String
* *
* Returns: The array representing the string. * Returns: The array representing the string.
*/ */
inout(char)[] get() inout pure nothrow @trusted @nogc inout(char)[] get() inout @nogc nothrow pure @trusted
{ {
return this.data[0 .. this.length_]; return this.data[0 .. this.length_];
} }
/// ///
nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Char array."); auto s = String("Char array.");
assert(s.get().length == 11); assert(s.get().length == 11);
@ -1003,7 +989,7 @@ struct String
* *
* Returns: Null-terminated string. * Returns: Null-terminated string.
*/ */
const(char)* toStringz() nothrow @nogc const(char)* toStringz() @nogc nothrow pure
{ {
reserve(length + 1); reserve(length + 1);
this.data[length] = '\0'; this.data[length] = '\0';
@ -1011,7 +997,7 @@ struct String
} }
/// ///
@nogc unittest @nogc pure unittest
{ {
auto s = String("C string."); auto s = String("C string.");
assert(s.toStringz()[0] == 'C'); assert(s.toStringz()[0] == 'C');
@ -1021,7 +1007,7 @@ struct String
/** /**
* Returns: The number of code units that are required to encode the string. * Returns: The number of code units that are required to encode the string.
*/ */
@property size_t length() const pure nothrow @safe @nogc @property size_t length() const @nogc nothrow pure @safe
{ {
return this.length_; return this.length_;
} }
@ -1030,7 +1016,7 @@ struct String
alias opDollar = length; alias opDollar = length;
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Piscis primuin a capite foetat."); auto s = String("Piscis primuin a capite foetat.");
assert(s.length == 31); assert(s.length == 31);
@ -1045,7 +1031,7 @@ struct String
* *
* Precondition: $(D_INLINECODE length > pos). * Precondition: $(D_INLINECODE length > pos).
*/ */
ref inout(char) opIndex(const size_t pos) inout pure nothrow @trusted @nogc ref inout(char) opIndex(const size_t pos) inout @nogc nothrow pure @trusted
in in
{ {
assert(length > pos); assert(length > pos);
@ -1056,7 +1042,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Alea iacta est."); auto s = String("Alea iacta est.");
assert(s[0] == 'A'); assert(s[0] == 'A');
@ -1067,19 +1053,19 @@ struct String
* Returns: Random access range that iterates over the string by bytes, in * Returns: Random access range that iterates over the string by bytes, in
* forward order. * forward order.
*/ */
ByCodeUnit!char opIndex() pure nothrow @trusted @nogc ByCodeUnit!char opIndex() @nogc nothrow pure @trusted
{ {
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
} }
/// Ditto. /// ditto
ByCodeUnit!(const char) opIndex() const pure nothrow @trusted @nogc ByCodeUnit!(const char) opIndex() const pure nothrow @trusted @nogc
{ {
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Plutarchus"); auto s = String("Plutarchus");
auto r = s[]; auto r = s[];
@ -1097,30 +1083,41 @@ struct String
assert(r.length == 8); assert(r.length == 8);
} }
///
@nogc pure @safe unittest
{
auto s = const String("Was ich vermag, soll gern geschehen. Goethe");
auto r1 = s[];
assert(r1.front == 'W');
auto r2 = r1[];
r1.popFront();
assert(r1.front == 'a');
assert(r2.front == 'W');
}
/** /**
* Returns: Forward range that iterates over the string by code points. * Returns: Forward range that iterates over the string by code points.
*/ */
ByCodePoint!char byCodePoint() pure nothrow @trusted @nogc ByCodePoint!char byCodePoint() @nogc nothrow pure @trusted
{ {
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
} }
/// Ditto. /// ditto
ByCodePoint!(const char) byCodePoint() const pure nothrow @trusted @nogc ByCodePoint!(const char) byCodePoint() const @nogc nothrow pure @trusted
{ {
return typeof(return)(this, this.data, this.data + length); return typeof(return)(this, this.data, this.data + length);
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Высоцкий"); auto s = String("Мне есть, что спеть, представ перед Всевышним.");
auto cp = s.byCodePoint(); auto cp = s.byCodePoint();
assert(cp.front == 'В'); assert(cp.front == 'М');
cp.popFront(); cp.popFront();
assert(cp.front == 'ы'); assert(cp.front == 'н');
cp.popFront();
assert(cp.front == 'с');
s = String("€"); s = String("€");
cp = s.byCodePoint(); cp = s.byCodePoint();
@ -1133,16 +1130,37 @@ struct String
assert(s.length == 4); assert(s.length == 4);
} }
///
@nogc pure @safe unittest
{
auto s = const String("Высоцкий");
auto cp1 = s.byCodePoint();
assert(cp1.front == 'В');
auto cp2 = cp1[];
cp1.popFront();
assert(cp1.front == 'ы');
assert(cp2.front == 'В');
cp2 = cp1.save();
cp1.popFront();
assert(cp1.front == 'с');
assert(cp2.front == 'ы');
}
/** /**
* Returns: $(D_KEYWORD true) if the string is empty. * Returns whether the string is empty.
*
* Returns: $(D_KEYWORD true) if the string is empty, $(D_KEYWORD false)
* otherwise.
*/ */
@property bool empty() const pure nothrow @safe @nogc @property bool empty() const @nogc nothrow pure @safe
{ {
return length == 0; return length == 0;
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
String s; String s;
assert(s.empty); assert(s.empty);
@ -1162,7 +1180,7 @@ struct String
* Precondition: $(D_INLINECODE i <= j && j <= length). * Precondition: $(D_INLINECODE i <= j && j <= length).
*/ */
ByCodeUnit!char opSlice(const size_t i, const size_t j) ByCodeUnit!char opSlice(const size_t i, const size_t j)
pure nothrow @trusted @nogc @nogc nothrow pure @trusted
in in
{ {
assert(i <= j); assert(i <= j);
@ -1173,9 +1191,9 @@ struct String
return typeof(return)(this, this.data + i, this.data + j); return typeof(return)(this, this.data + i, this.data + j);
} }
/// Ditto. /// ditto
ByCodeUnit!(const char) opSlice(const size_t i, const size_t j) ByCodeUnit!(const char) opSlice(const size_t i, const size_t j)
const pure nothrow @trusted @nogc const @nogc nothrow pure @trusted
in in
{ {
assert(i <= j); assert(i <= j);
@ -1187,7 +1205,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Vladimir Soloviev"); auto s = String("Vladimir Soloviev");
auto r = s[9 .. $]; auto r = s[9 .. $];
@ -1240,7 +1258,7 @@ struct String
return this; return this;
} }
/// Ditto. /// ditto
ref String opAssign(S)(ref S that) @trusted ref String opAssign(S)(ref S that) @trusted
if (is(Unqual!S == String)) if (is(Unqual!S == String))
{ {
@ -1251,7 +1269,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Черная, потом пропахшая выть!"); auto s = String("Черная, потом пропахшая выть!");
s = String("Как мне тебя не ласкать, не любить?"); s = String("Как мне тебя не ласкать, не любить?");
@ -1268,10 +1286,10 @@ struct String
* *
* Throws: $(D_PSYMBOL UTFException). * Throws: $(D_PSYMBOL UTFException).
*/ */
ref String opAssign(S)(S that) nothrow ref String opAssign(S)(S that)
if (!isInfinite!S if (!isInfinite!S
&& isInputRange!S && isInputRange!S
&& isSomeChar!(ElementEncodingType!S)) && isSomeChar!(ElementType!S))
{ {
this.length_ = 0; this.length_ = 0;
insertBack(that); insertBack(that);
@ -1279,7 +1297,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Оловом светится лужная голь..."); auto s = String("Оловом светится лужная голь...");
s = "Грустная песня, ты - русская боль."; s = "Грустная песня, ты - русская боль.";
@ -1301,7 +1319,7 @@ struct String
return cmp(this.data[0 .. length], that.data[0 .. that.length]); return cmp(this.data[0 .. length], that.data[0 .. that.length]);
} }
/// Ditto. /// ditto
int opCmp(S)(ByCodeUnit!S that) const @trusted int opCmp(S)(ByCodeUnit!S that) const @trusted
if (is(Unqual!S == char)) if (is(Unqual!S == char))
{ {
@ -1309,7 +1327,7 @@ struct String
that.begin[0 .. that.end - that.begin]); that.begin[0 .. that.end - that.begin]);
} }
/// Ditto. /// ditto
int opCmp(S)(ByCodePoint!S that) const @trusted int opCmp(S)(ByCodePoint!S that) const @trusted
if (is(Unqual!S == char)) if (is(Unqual!S == char))
{ {
@ -1317,14 +1335,14 @@ struct String
that.begin[0 .. that.end - that.begin]); that.begin[0 .. that.end - that.begin]);
} }
/// Ditto. /// ditto
int opCmp()(const char[] that) const @trusted int opCmp()(const char[] that) const @trusted
{ {
return cmp(this.data[0 .. length], that); return cmp(this.data[0 .. length], that);
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
assert(String("Голубая кофта.") < String("Синие глаза.")); assert(String("Голубая кофта.") < String("Синие глаза."));
assert(String("Никакой я правды") < String("милой не сказал")[]); assert(String("Никакой я правды") < String("милой не сказал")[]);
@ -1362,7 +1380,7 @@ struct String
that.begin[0 .. that.end - that.begin]); that.begin[0 .. that.end - that.begin]);
} }
/// Ditto. /// ditto
bool opEquals(S)(ByCodePoint!S that) const @trusted bool opEquals(S)(ByCodePoint!S that) const @trusted
if (is(Unqual!S == char)) if (is(Unqual!S == char))
{ {
@ -1370,14 +1388,14 @@ struct String
that.begin[0 .. that.end - that.begin]); that.begin[0 .. that.end - that.begin]);
} }
/// Ditto. /// ditto
bool opEquals()(const char[] that) const @trusted bool opEquals()(const char[] that) const @trusted
{ {
return equal(this.data[0 .. length], that); return equal(this.data[0 .. length], that);
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
assert(String("Милая спросила:") != String("Крутит ли метель?")); assert(String("Милая спросила:") != String("Крутит ли метель?"));
assert(String("Затопить бы печку,") != String("постелить постель.")[]); assert(String("Затопить бы печку,") != String("постелить постель.")[]);
@ -1404,13 +1422,13 @@ struct String
* Precondition: $(D_INLINECODE length > pos). * Precondition: $(D_INLINECODE length > pos).
*/ */
ref char opIndexAssign(const char value, const size_t pos) ref char opIndexAssign(const char value, const size_t pos)
pure nothrow @safe @nogc @nogc nothrow pure @safe
{ {
return opIndex(pos) = value; return opIndex(pos) = value;
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("alea iacta est."); auto s = String("alea iacta est.");
@ -1435,7 +1453,7 @@ struct String
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
private unittest @nogc pure @safe unittest
{ {
auto s1 = String("Buttercup"); auto s1 = String("Buttercup");
auto s2 = String("Cap"); auto s2 = String("Cap");
@ -1443,26 +1461,26 @@ struct String
assert(s2 == "cup"); assert(s2 == "cup");
} }
/// Ditto. /// ditto
ByCodeUnit!char opIndexAssign(const char value) pure nothrow @safe @nogc ByCodeUnit!char opIndexAssign(const char value) @nogc nothrow pure @safe
{ {
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
private unittest @nogc pure @safe unittest
{ {
auto s1 = String("Wow"); auto s1 = String("Wow");
s1[] = 'a'; s1[] = 'a';
assert(s1 == "aaa"); assert(s1 == "aaa");
} }
/// Ditto. /// ditto
ByCodeUnit!char opIndexAssign(const char[] value) pure nothrow @safe @nogc ByCodeUnit!char opIndexAssign(const char[] value) @nogc nothrow pure @safe
{ {
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
private unittest @nogc pure @safe unittest
{ {
auto s1 = String("ö"); auto s1 = String("ö");
s1[] = "oe"; s1[] = "oe";
@ -1498,7 +1516,7 @@ struct String
} }
/// ///
@nogc @safe unittest @nogc pure @safe unittest
{ {
auto s = String("Из пословицы слова не выкинешь."); auto s = String("Из пословицы слова не выкинешь.");
@ -1507,7 +1525,7 @@ struct String
assert(s.length == 38); assert(s.length == 38);
auto byCodePoint = s.byCodePoint(); auto byCodePoint = s.byCodePoint();
byCodePoint.popFrontN(8); std.range.popFrontN(byCodePoint, 8);
assert(s.remove(byCodePoint).count == 0); assert(s.remove(byCodePoint).count == 0);
assert(s == "Из слова"); assert(s == "Из слова");
@ -1534,7 +1552,7 @@ struct String
size_t insertAfter(T, R)(R r, T el) @trusted size_t insertAfter(T, R)(R r, T el) @trusted
if ((isSomeChar!T || (!isInfinite!T if ((isSomeChar!T || (!isInfinite!T
&& isInputRange!T && isInputRange!T
&& isSomeChar!(ElementEncodingType!T))) && isSomeChar!(ElementType!T)))
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
in in
{ {
@ -1552,7 +1570,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Казнить нельзя помиловать."); auto s = String("Казнить нельзя помиловать.");
s.insertAfter(s[0 .. 27], ","); s.insertAfter(s[0 .. 27], ",");
@ -1567,7 +1585,7 @@ struct String
size_t insertBefore(T, R)(R r, T el) @trusted size_t insertBefore(T, R)(R r, T el) @trusted
if ((isSomeChar!T || (!isInfinite!T if ((isSomeChar!T || (!isInfinite!T
&& isInputRange!T && isInputRange!T
&& isSomeChar!(ElementEncodingType!T))) && isSomeChar!(ElementType!T)))
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
in in
{ {
@ -1581,7 +1599,7 @@ struct String
} }
/// ///
@safe @nogc unittest @nogc pure @safe unittest
{ {
auto s = String("Казнить нельзя помиловать."); auto s = String("Казнить нельзя помиловать.");
s.insertBefore(s[27 .. $], ","); s.insertBefore(s[27 .. $], ",");
@ -1594,3 +1612,67 @@ struct String
mixin DefaultAllocator; mixin DefaultAllocator;
} }
// Postblit works.
@nogc pure @safe unittest
{
void internFunc(String arg)
{
}
void middleFunc(S...)(S args)
{
foreach (arg; args)
{
internFunc(arg);
}
}
void topFunc(String args)
{
middleFunc(args);
}
topFunc(String("asdf"));
}
// Const range produces mutable ranges.
@nogc pure @safe unittest
{
auto s = const String("И снизу лед, и сверху - маюсь между.");
{
const constRange = s[];
auto fromConstRange = constRange[];
fromConstRange.popFront();
assert(fromConstRange.front == s[1]);
fromConstRange = constRange[0 .. $];
fromConstRange.popFront();
assert(fromConstRange.front == s[1]);
assert(constRange.get() is s.get());
}
{
const constRange = s.byCodePoint();
auto fromConstRange = constRange[];
fromConstRange.popFront();
assert(fromConstRange.front == ' ');
}
}
// Can pop multibyte characters.
@nogc pure @safe unittest
{
auto s = String("\U00024B62\U00002260");
auto range = s.byCodePoint();
range.popFront();
assert(!range.empty);
range.popFront();
assert(range.empty);
range = s.byCodePoint();
range.popFront();
s[$ - 3] = 0xf0;
assertThrown!UTFException(&(range.popFront));
}

235
source/tanya/conv.d Normal file
View File

@ -0,0 +1,235 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This module provides functions for converting between different types.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/conv.d,
* tanya/conv.d)
*/
module tanya.conv;
import tanya.memory;
import tanya.memory.op;
import tanya.meta.trait;
/**
* Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
* given arguments.
*
* If $(D_PARAM T) is a $(D_KEYWORD class), emplace returns a class reference
* of type $(D_PARAM T), otherwise a pointer to the constructed object is
* returned.
*
* If $(D_PARAM T) is a nested class inside another class, $(D_PARAM outer)
* should be an instance of the outer class.
*
* $(D_PARAM args) are arguments for the constructor of $(D_PARAM T). If
* $(D_PARAM T) isn't an aggregate type and doesn't have a constructor,
* $(D_PARAM memory) can be initialized to `args[0]` if `Args.length == 1`,
* `Args[0]` should be implicitly convertible to $(D_PARAM T) then.
*
* Params:
* T = Constructed type.
* U = Type of the outer class if $(D_PARAM T) is a nested class.
* Args = Types of the constructor arguments if $(D_PARAM T) has a constructor
* or the type of the initial value.
* outer = Outer class instance if $(D_PARAM T) is a nested class.
* args = Constructor arguments if $(D_PARAM T) has a constructor or the
* initial value.
*
* Returns: New instance of type $(D_PARAM T) constructed in $(D_PARAM memory).
*
* Precondition: `memory.length == stateSize!T`.
* Postcondition: $(D_PARAM memory) and the result point to the same memory.
*/
T emplace(T, U, Args...)(void[] memory, U outer, auto ref Args args)
if (!isAbstractClass!T && isInnerClass!T && is(typeof(T.outer) == U))
in
{
assert(memory.length >= stateSize!T);
}
out (result)
{
assert(memory.ptr is (() @trusted => cast(void*) result)());
}
body
{
copy(typeid(T).initializer, memory);
auto result = (() @trusted => cast(T) memory.ptr)();
result.outer = outer;
static if (is(typeof(result.__ctor(args))))
{
result.__ctor(args);
}
return result;
}
/// ditto
T emplace(T, Args...)(void[] memory, auto ref Args args)
if (is(T == class) && !isAbstractClass!T && !isInnerClass!T)
in
{
assert(memory.length == stateSize!T);
}
out (result)
{
assert(memory.ptr is (() @trusted => cast(void*) result)());
}body
{
copy(typeid(T).initializer, memory);
auto result = (() @trusted => cast(T) memory.ptr)();
static if (is(typeof(result.__ctor(args))))
{
result.__ctor(args);
}
return result;
}
///
@nogc nothrow pure @safe unittest
{
import tanya.memory : stateSize;
class C
{
int i = 5;
class Inner
{
int i;
this(int param) pure nothrow @safe @nogc
{
this.i = param;
}
}
}
ubyte[stateSize!C] memory1;
ubyte[stateSize!(C.Inner)] memory2;
auto c = emplace!C(memory1);
assert(c.i == 5);
auto inner = emplace!(C.Inner)(memory2, c, 8);
assert(c.i == 5);
assert(inner.i == 8);
assert(inner.outer is c);
}
/// ditto
T* emplace(T, Args...)(void[] memory, auto ref Args args)
if (!isAggregateType!T && (Args.length <= 1))
in
{
assert(memory.length >= T.sizeof);
}
out (result)
{
assert(memory.ptr is result);
}
body
{
auto result = (() @trusted => cast(T*) memory.ptr)();
static if (Args.length == 1)
{
*result = T(args[0]);
}
else
{
*result = T.init;
}
return result;
}
/// ditto
T* emplace(T, Args...)(void[] memory, auto ref Args args)
if (!isPolymorphicType!T && isAggregateType!T)
in
{
assert(memory.length >= T.sizeof);
}
out (result)
{
assert(memory.ptr is result);
}
body
{
auto result = (() @trusted => cast(T*) memory.ptr)();
static if (!hasElaborateAssign!T && isAssignable!T)
{
*result = T.init;
}
else
{
static const T init = T.init;
copy((cast(void*) &init)[0 .. T.sizeof], memory);
}
static if (Args.length == 0)
{
static assert(is(typeof({ static T t; })),
"Default constructor is disabled");
}
else static if (is(typeof(T(args))))
{
*result = T(args);
}
else static if (is(typeof(result.__ctor(args))))
{
result.__ctor(args);
}
else
{
static assert(false,
"Unable to construct value with the given arguments");
}
return result;
}
///
@nogc nothrow pure @safe unittest
{
ubyte[4] memory;
auto i = emplace!int(memory);
static assert(is(typeof(i) == int*));
assert(*i == 0);
i = emplace!int(memory, 5);
assert(*i == 5);
static struct S
{
int i;
@disable this();
@disable this(this);
this(int i) @nogc nothrow pure @safe
{
this.i = i;
}
}
auto s = emplace!S(memory, 8);
static assert(is(typeof(s) == S*));
assert(s.i == 8);
}
// Handles "Cannot access frame pointer" error.
@nogc nothrow pure @safe unittest
{
struct F
{
~this() @nogc nothrow pure @safe
{
}
}
static assert(is(typeof(emplace!F((void[]).init))));
}

View File

@ -0,0 +1,501 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Functions operating on ASCII characters.
*
* ASCII is $(B A)merican $(B S)tandard $(B C)ode for $(B I)nformation
* $(B I)nterchange.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/encoding/ascii.d,
* tanya/encoding/ascii.d)
*/
module tanya.encoding.ascii;
import tanya.meta.trait;
const string fullHexDigits = "0123456789ABCDEFabcdef"; /// 0..9A..Fa..f.
const string hexDigits = "0123456789ABCDEF"; /// 0..9A..F.
const string lowerHexDigits = "0123456789abcdef"; /// 0..9a..f.
const string digits = "0123456789"; /// 0..9.
const string octalDigits = "01234567"; /// 0..7.
/// A..Za..z.
const string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const string uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /// A..Z.
const string lowercase = "abcdefghijklmnopqrstuvwxyz"; /// a..z.
/**
* Whitespace, Horizontal Tab (HT), Line Feed (LF), Carriage Return (CR),
* Vertical Tab (VT) or Form Feed (FF).
*/
const string whitespace = "\t\n\v\f\r ";
/// Letter case specifier.
enum LetterCase : bool
{
upper, /// Uppercase.
lower, /// Lowercase.
}
/**
* Checks for an uppecase alphabetic character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is an uppercase alphabetic
* character, $(D_KEYWORD false) otherwise.
*/
bool isUpper(C)(C c)
if (isSomeChar!C)
{
return (c >= 'A') && (c <= 'Z');
}
///
pure nothrow @safe @nogc unittest
{
assert(isUpper('A'));
assert(isUpper('Z'));
assert(isUpper('L'));
assert(!isUpper('a'));
assert(!isUpper('!'));
}
/**
* Checks for a lowercase alphabetic character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a lowercase alphabetic
* character, $(D_KEYWORD false) otherwise.
*/
bool isLower(C)(C c)
if (isSomeChar!C)
{
return (c >= 'a') && (c <= 'z');
}
///
pure nothrow @safe @nogc unittest
{
assert(isLower('a'));
assert(isLower('z'));
assert(isLower('l'));
assert(!isLower('A'));
assert(!isLower('!'));
}
/**
* Checks for an alphabetic character (upper- or lowercase).
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is an alphabetic character,
* $(D_KEYWORD false) otherwise.
*/
bool isAlpha(C)(C c)
if (isSomeChar!C)
{
return isUpper(c) || isLower(c);
}
///
pure nothrow @safe @nogc unittest
{
assert(isAlpha('A'));
assert(isAlpha('Z'));
assert(isAlpha('L'));
assert(isAlpha('a'));
assert(isAlpha('z'));
assert(isAlpha('l'));
assert(!isAlpha('!'));
}
/**
* Checks for a digit.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a digit,
* $(D_KEYWORD false) otherwise.
*/
bool isDigit(C)(C c)
if (isSomeChar!C)
{
return (c >= '0') && (c <= '9');
}
///
pure nothrow @safe @nogc unittest
{
assert(isDigit('0'));
assert(isDigit('1'));
assert(isDigit('2'));
assert(isDigit('3'));
assert(isDigit('4'));
assert(isDigit('5'));
assert(isDigit('6'));
assert(isDigit('7'));
assert(isDigit('8'));
assert(isDigit('9'));
assert(!isDigit('a'));
assert(!isDigit('!'));
}
/**
* Checks for an alphabetic character (upper- or lowercase) or a digit.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is an alphabetic character or a
* digit, $(D_KEYWORD false) otherwise.
*/
bool isAlphaNum(C)(C c)
if (isSomeChar!C)
{
return isAlpha(c) || isDigit(c);
}
///
pure nothrow @safe @nogc unittest
{
assert(isAlphaNum('0'));
assert(isAlphaNum('1'));
assert(isAlphaNum('9'));
assert(isAlphaNum('A'));
assert(isAlphaNum('Z'));
assert(isAlphaNum('L'));
assert(isAlphaNum('a'));
assert(isAlphaNum('z'));
assert(isAlphaNum('l'));
assert(!isAlphaNum('!'));
}
/**
* Checks for a 7-bit ASCII character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is an ASCII character,
* $(D_KEYWORD false) otherwise.
*/
bool isASCII(C)(C c)
if (isSomeChar!C)
{
return c < 128;
}
///
pure nothrow @safe @nogc unittest
{
assert(isASCII('0'));
assert(isASCII('L'));
assert(isASCII('l'));
assert(isASCII('!'));
assert(!isASCII('©'));
assert(!isASCII('§'));
assert(!isASCII(char.init)); // 0xFF
assert(!isASCII(wchar.init)); // 0xFFFF
assert(!isASCII(dchar.init)); // 0xFFFF
}
/**
* Checks for a control character.
*
* Control characters are non-printable characters. Their ASCII codes are those
* between 0x00 (NUL) and 0x1f (US), and 0x7f (DEL).
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a control character,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isPrintable), $(D_PSYMBOL isGraphical).
*/
bool isControl(C)(C c)
if (isSomeChar!C)
{
return (c <= 0x1f) || (c == 0x7f);
}
///
pure nothrow @safe @nogc unittest
{
assert(isControl('\t'));
assert(isControl('\0'));
assert(isControl('\u007f'));
assert(!isControl(' '));
assert(!isControl('a'));
assert(!isControl(char.init)); // 0xFF
assert(!isControl(wchar.init)); // 0xFFFF
}
/**
* Checks for a whitespace character.
*
* Whitespace characters are:
*
* $(UL
* $(LI Whitespace)
* $(LI Horizontal Tab (HT))
* $(LI Line Feed (LF))
* $(LI Carriage Return (CR))
* $(LI Vertical Tab (VT))
* $(LI Form Feed (FF))
* )
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a whitespace character,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL whitespace).
*/
bool isWhite(C)(C c)
if (isSomeChar!C)
{
return ((c >= 0x09) && (c <= 0x0d)) || (c == 0x20);
}
///
pure nothrow @safe @nogc unittest
{
assert(isWhite('\t'));
assert(isWhite('\n'));
assert(isWhite('\v'));
assert(isWhite('\f'));
assert(isWhite('\r'));
assert(isWhite(' '));
}
/**
* Checks for a graphical character.
*
* Graphical characters are printable characters but whitespace characters.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a control character,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isControl), $(D_PSYMBOL isWhite).
*/
bool isGraphical(C)(C c)
if (isSomeChar!C)
{
return (c > 0x20) && (c < 0x7f);
}
///
pure nothrow @safe @nogc unittest
{
assert(isGraphical('a'));
assert(isGraphical('0'));
assert(!isGraphical('\u007f'));
assert(!isGraphical('§'));
assert(!isGraphical('\n'));
assert(!isGraphical(' '));
}
/**
* Checks for a printable character.
*
* This is the opposite of a control character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a control character,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isControl).
*/
bool isPrintable(C)(C c)
if (isSomeChar!C)
{
return (c >= 0x20) && (c < 0x7f);
}
///
pure nothrow @safe @nogc unittest
{
assert(isPrintable('a'));
assert(isPrintable('0'));
assert(!isPrintable('\u007f'));
assert(!isPrintable('§'));
assert(!isPrintable('\n'));
assert(isPrintable(' '));
}
/**
* Checks for a hexadecimal digit.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a hexadecimal digit,
* $(D_KEYWORD false) otherwise.
*/
bool isHexDigit(C)(C c)
if (isSomeChar!C)
{
return ((c >= '0') && (c <= '9'))
|| ((c >= 'a') && (c <= 'f'))
|| ((c >= 'A') && (c <= 'F'));
}
///
pure nothrow @safe @nogc unittest
{
assert(isHexDigit('0'));
assert(isHexDigit('1'));
assert(isHexDigit('8'));
assert(isHexDigit('9'));
assert(isHexDigit('A'));
assert(isHexDigit('F'));
assert(!isHexDigit('G'));
assert(isHexDigit('a'));
assert(isHexDigit('f'));
assert(!isHexDigit('g'));
}
/**
* Checks for an octal character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is an octal character,
* $(D_KEYWORD false) otherwise.
*/
bool isOctalDigit(C)(C c)
if (isSomeChar!C)
{
return (c >= '0') && (c <= '7');
}
///
pure nothrow @safe @nogc unittest
{
assert(isOctalDigit('0'));
assert(isOctalDigit('1'));
assert(isOctalDigit('2'));
assert(isOctalDigit('3'));
assert(isOctalDigit('4'));
assert(isOctalDigit('5'));
assert(isOctalDigit('6'));
assert(isOctalDigit('7'));
assert(!isOctalDigit('8'));
}
/**
* Checks for a octal character.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM c) is a octal character,
* $(D_KEYWORD false) otherwise.
*/
bool isPunctuation(C)(C c)
if (isSomeChar!C)
{
return ((c >= 0x21) && (c <= 0x2f))
|| ((c >= 0x3a) && (c <= 0x40))
|| ((c >= 0x5b) && (c <= 0x60))
|| ((c >= 0x7b) && (c <= 0x7e));
}
///
pure nothrow @safe @nogc unittest
{
assert(isPunctuation('!'));
assert(isPunctuation(':'));
assert(isPunctuation('\\'));
assert(isPunctuation('|'));
assert(!isPunctuation('0'));
assert(!isPunctuation(' '));
}
/**
* Converts $(D_PARAM c) to uppercase.
*
* If $(D_PARAM c) is not a lowercase character, $(D_PARAM c) is returned
* unchanged.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: The lowercase of $(D_PARAM c) if available, just $(D_PARAM c)
* otherwise.
*/
C toUpper(C)(const C c)
if (isSomeChar!C)
{
return isLower(c) ? (cast(C) (c - 32)) : c;
}
///
pure nothrow @safe @nogc unittest
{
assert(toUpper('a') == 'A');
assert(toUpper('A') == 'A');
assert(toUpper('!') == '!');
}
/**
* Converts $(D_PARAM c) to lowercase.
*
* If $(D_PARAM c) is not an uppercase character, $(D_PARAM c) is returned
* unchanged.
*
* Params:
* C = Some character type.
* c = Some character.
*
* Returns: The uppercase of $(D_PARAM c) if available, just $(D_PARAM c)
* otherwise.
*/
C toLower(C)(const C c)
if (isSomeChar!C)
{
return isUpper(c) ? (cast(C) (c + 32)) : c;
}
///
pure nothrow @safe @nogc unittest
{
assert(toLower('A') == 'a');
assert(toLower('a') == 'a');
assert(toLower('!') == '!');
}

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This package provides tools to work with text encodings.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/encoding/package.d,
* tanya/encoding/package.d)
*/
module tanya.encoding;
public import tanya.encoding.ascii;

66
source/tanya/exception.d Normal file
View File

@ -0,0 +1,66 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Common exceptions and errors.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/exception.d,
* tanya/exception.d)
*/
module tanya.exception;
import tanya.conv;
import tanya.memory;
/**
* Error thrown if memory allocation fails.
*/
final class OutOfMemoryError : Error
{
/**
* Constructs new error.
*
* Params:
* msg = The message for the exception.
* file = The file where the exception occurred.
* line = The line number where the exception occurred.
* next = The previous exception in the chain of exceptions, if any.
*/
this(string msg = "Out of memory",
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null) @nogc nothrow pure @safe
{
super(msg, file, line, next);
}
/// ditto
this(string msg,
Throwable next,
string file = __FILE__,
size_t line = __LINE__) @nogc nothrow pure @safe
{
super(msg, file, line, next);
}
}
/**
* Allocates $(D_PSYMBOL OutOfMemoryError) in a static storage and throws it.
*
* Params:
* msg = Custom error message.
*
* Throws: $(D_PSYMBOL OutOfMemoryError).
*/
void onOutOfMemoryError(string msg = "Out of memory")
@nogc nothrow pure @trusted
{
static ubyte[stateSize!OutOfMemoryError] memory;
alias PureType = OutOfMemoryError function(string) @nogc nothrow pure;
throw (cast(PureType) () => emplace!OutOfMemoryError(memory))(msg);
}

View File

@ -64,7 +64,7 @@ template to(To)
return from; return from;
} }
/// Ditto. /// ditto
To to(From)(From from) To to(From)(From from)
if (is(Unqual!To == Unqual!From) || (isNumeric!From && isFloatingPoint!To)) if (is(Unqual!To == Unqual!From) || (isNumeric!From && isFloatingPoint!To))
{ {
@ -358,7 +358,7 @@ private @nogc unittest
defaultAllocator.dispose(exception); defaultAllocator.dispose(exception);
} }
/// Ditto. /// ditto
To to(To, From)(auto ref const From from) To to(To, From)(auto ref const From from)
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool)) if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
{ {
@ -443,7 +443,7 @@ pure nothrow @safe @nogc unittest
assert(false.to!int == 0); assert(false.to!int == 0);
} }
/// Ditto. /// ditto
To to(To, From)(const From from) To to(To, From)(const From from)
if (is(Unqual!From == bool) && is(Unqual!To == String)) if (is(Unqual!From == bool) && is(Unqual!To == String))
{ {

File diff suppressed because it is too large Load Diff

View File

@ -15,9 +15,9 @@
module tanya.math.mp; module tanya.math.mp;
import std.algorithm; import std.algorithm;
import std.ascii;
import std.range; import std.range;
import tanya.container.array; import tanya.container.array;
import tanya.encoding.ascii;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
@ -75,7 +75,7 @@ struct Integer
this = value; this = value;
} }
/// Ditto. /// ditto
this(T)(ref T value, shared Allocator allocator = defaultAllocator) this(T)(ref T value, shared Allocator allocator = defaultAllocator)
if (is(Unqual!T == Integer)) if (is(Unqual!T == Integer))
{ {
@ -83,9 +83,8 @@ struct Integer
this = value; this = value;
} }
/// Ditto. /// ditto
this(T)(T value, shared Allocator allocator = defaultAllocator) this(T)(T value, shared Allocator allocator = defaultAllocator)
nothrow @safe @nogc
if (is(T == Integer)) if (is(T == Integer))
{ {
this(allocator); this(allocator);
@ -104,7 +103,7 @@ struct Integer
} }
} }
/// Ditto. /// ditto
this(shared Allocator allocator) pure nothrow @safe @nogc this(shared Allocator allocator) pure nothrow @safe @nogc
in in
{ {
@ -156,6 +155,7 @@ struct Integer
} }
} }
///
nothrow @safe @nogc unittest nothrow @safe @nogc unittest
{ {
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ]; ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
@ -173,8 +173,7 @@ struct Integer
* *
* Precondition: $(D_INLINECODE allocator !is null) * Precondition: $(D_INLINECODE allocator !is null)
*/ */
this(R)(R value, this(R)(R value, shared Allocator allocator = defaultAllocator)
shared Allocator allocator = defaultAllocator)
if (isBidirectionalRange!R && hasLength!R if (isBidirectionalRange!R && hasLength!R
&& is(Unqual!(ElementType!R) == ubyte)) && is(Unqual!(ElementType!R) == ubyte))
{ {
@ -280,6 +279,19 @@ struct Integer
} }
} }
///
private nothrow @safe @nogc unittest
{
{
Integer i;
assert(i.length == 0);
}
{
auto i = Integer(-123456789);
assert(i.length == 4);
}
}
/** /**
* Assigns a new value. * Assigns a new value.
* *
@ -323,7 +335,7 @@ struct Integer
return this; return this;
} }
/// Ditto. /// ditto
ref Integer opAssign(T)(ref T value) @trusted ref Integer opAssign(T)(ref T value) @trusted
if (is(Unqual!T == Integer)) if (is(Unqual!T == Integer))
{ {
@ -335,7 +347,7 @@ struct Integer
return this; return this;
} }
/// Ditto. /// ditto
ref Integer opAssign(T)(T value) nothrow @safe @nogc ref Integer opAssign(T)(T value) nothrow @safe @nogc
if (is(T == Integer)) if (is(T == Integer))
{ {
@ -359,7 +371,7 @@ struct Integer
return this.size > 0; return this.size > 0;
} }
/// Ditto. /// ditto
T opCast(T)() const T opCast(T)() const
if (isIntegral!T && isUnsigned!T) if (isIntegral!T && isUnsigned!T)
{ {
@ -373,7 +385,7 @@ struct Integer
return ret; return ret;
} }
/// Ditto. /// ditto
T opCast(T)() const T opCast(T)() const
if (isIntegral!T && isSigned!T) if (isIntegral!T && isSigned!T)
{ {
@ -405,7 +417,7 @@ struct Integer
assert(cast(long) integer == 0); assert(cast(long) integer == 0);
} }
/* trim unused digits /* Trim unused digits.
* *
* This is used to ensure that leading zero digits are * This is used to ensure that leading zero digits are
* trimed and the leading "size" digit will be non-zero * trimed and the leading "size" digit will be non-zero
@ -665,7 +677,7 @@ struct Integer
assert(integer1 > integer2); assert(integer1 > integer2);
} }
/// Ditto. /// ditto
int opCmp(I)(const I that) const int opCmp(I)(const I that) const
if (isIntegral!I) if (isIntegral!I)
{ {
@ -777,7 +789,7 @@ struct Integer
} }
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : "-")(auto ref const Integer operand) ref Integer opOpAssign(string op : "-")(auto ref const Integer operand)
{ {
if (this.sign != operand.sign) if (this.sign != operand.sign)
@ -825,7 +837,7 @@ struct Integer
} }
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : "*")(auto ref const Integer operand) ref Integer opOpAssign(string op : "*")(auto ref const Integer operand)
{ {
const digits = this.size + operand.size + 1; const digits = this.size + operand.size + 1;
@ -849,7 +861,7 @@ struct Integer
assert(h1 == 56088); assert(h1 == 56088);
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : "/")(auto ref const Integer operand) ref Integer opOpAssign(string op : "/")(auto ref const Integer operand)
in in
{ {
@ -861,7 +873,7 @@ struct Integer
return this; return this;
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : "%")(auto ref const Integer operand) ref Integer opOpAssign(string op : "%")(auto ref const Integer operand)
in in
{ {
@ -894,7 +906,7 @@ struct Integer
assert(h1 == 123); assert(h1 == 123);
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : ">>")(const size_t operand) ref Integer opOpAssign(string op : ">>")(const size_t operand)
{ {
if (operand == 0) if (operand == 0)
@ -956,7 +968,7 @@ struct Integer
assert(integer == 0); assert(integer == 0);
} }
/// Ditto. /// ditto
ref Integer opOpAssign(string op : "<<")(const size_t operand) ref Integer opOpAssign(string op : "<<")(const size_t operand)
{ {
const step = operand / digitBitCount; const step = operand / digitBitCount;
@ -1015,7 +1027,7 @@ struct Integer
return ret; return ret;
} }
/// Ditto. /// ditto
Integer opUnary(string op : "-")() const Integer opUnary(string op : "-")() const
{ {
auto ret = Integer(this, allocator); auto ret = Integer(this, allocator);
@ -1056,7 +1068,7 @@ struct Integer
assert(h2 == ~cast(ubyte) 79); assert(h2 == ~cast(ubyte) 79);
} }
/// Ditto. /// ditto
ref Integer opUnary(string op : "++")() ref Integer opUnary(string op : "++")()
{ {
if (this.sign) if (this.sign)
@ -1070,7 +1082,7 @@ struct Integer
return this; return this;
} }
/// Ditto. /// ditto
ref Integer opUnary(string op : "--")() ref Integer opUnary(string op : "--")()
{ {
if (this.size == 0) if (this.size == 0)
@ -1140,7 +1152,7 @@ struct Integer
mixin("return Integer(this, allocator) " ~ op ~ "= operand;"); mixin("return Integer(this, allocator) " ~ op ~ "= operand;");
} }
/// Ditto. /// ditto
Integer opBinary(string op)(const auto ref Integer operand) const Integer opBinary(string op)(const auto ref Integer operand) const
if (op == "/" || op == "%") if (op == "/" || op == "%")
in in
@ -1152,7 +1164,7 @@ struct Integer
mixin("return Integer(this, allocator) " ~ op ~ "= operand;"); mixin("return Integer(this, allocator) " ~ op ~ "= operand;");
} }
/// Ditto. /// ditto
Integer opBinary(string op)(const size_t operand) const Integer opBinary(string op)(const size_t operand) const
if (op == "<<" || op == ">>") if (op == "<<" || op == ">>")
{ {

View File

@ -0,0 +1,165 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Number theory.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/math/nbtheory.d,
* tanya/math/nbtheory.d)
*/
module tanya.math.nbtheory;
import tanya.math.mp;
import tanya.meta.trait;
version (TanyaNative)
{
}
else
{
import core.math : fabs;
import std.math : log;
}
/**
* Calculates the absolute value of a number.
*
* Params:
* I = Value type.
* x = Value.
*
* Returns: Absolute value of $(D_PARAM x).
*/
I abs(I)(I x)
if (isIntegral!I)
{
static if (isSigned!I)
{
return x >= 0 ? x : -x;
}
else
{
return x;
}
}
///
pure nothrow @safe @nogc unittest
{
int i = -1;
assert(i.abs == 1);
static assert(is(typeof(i.abs) == int));
uint u = 1;
assert(u.abs == 1);
static assert(is(typeof(u.abs) == uint));
}
version (D_Ddoc)
{
/// ditto
I abs(I)(I x)
if (isFloatingPoint!I);
}
else version (TanyaNative)
{
extern I abs(I)(I number) pure nothrow @safe @nogc
if (isFloatingPoint!I);
}
else
{
I abs(I)(I x)
if (isFloatingPoint!I)
{
return fabs(cast(real) x);
}
}
///
pure nothrow @safe @nogc unittest
{
float f = -1.64;
assert(f.abs == 1.64F);
static assert(is(typeof(f.abs) == float));
double d = -1.64;
assert(d.abs == 1.64);
static assert(is(typeof(d.abs) == double));
real r = -1.64;
assert(r.abs == 1.64L);
static assert(is(typeof(r.abs) == real));
}
/// ditto
I abs(I : Integer)(const auto ref I x)
{
auto result = Integer(x, x.allocator);
result.sign = Sign.positive;
return result;
}
/// ditto
I abs(I : Integer)(I x)
{
x.sign = Sign.positive;
return x;
}
version (D_Ddoc)
{
/**
* Calculates natural logarithm of $(D_PARAM x).
*
* Params:
* x = Argument.
*
* Returns: Natural logarithm of $(D_PARAM x).
*/
float ln(float x) pure nothrow @safe @nogc;
/// ditto
double ln(double x) pure nothrow @safe @nogc;
/// ditto
real ln(real x) pure nothrow @safe @nogc;
}
else version (TanyaNative)
{
extern float ln(float x) pure nothrow @safe @nogc;
extern double ln(double x) pure nothrow @safe @nogc;
extern real ln(real x) pure nothrow @safe @nogc;
}
else
{
float ln(float x) pure nothrow @safe @nogc
{
return log(x);
}
double ln(double x) pure nothrow @safe @nogc
{
return log(x);
}
alias ln = log;
}
///
pure nothrow @safe @nogc unittest
{
import tanya.math;
assert(isNaN(ln(-7.389f)));
assert(isNaN(ln(-7.389)));
assert(isNaN(ln(-7.389L)));
assert(isInfinity(ln(0.0f)));
assert(isInfinity(ln(0.0)));
assert(isInfinity(ln(0.0L)));
assert(ln(1.0f) == 0.0f);
assert(ln(1.0) == 0.0);
assert(ln(1.0L) == 0.0L);
}

View File

@ -5,6 +5,13 @@
/** /**
* This package provides mathematical functions. * This package provides mathematical functions.
* *
* The $(D_PSYMBOL tanya.math) package itself provides only representation
* functions for built-in types, such as functions that provide information
* about internal representation of floating-point numbers and low-level
* operatons on these. Actual mathematical functions and additional types can
* be found in its submodules. $(D_PSYMBOL tanya.math) doesn't import any
* submodules publically, they should be imported explicitly.
*
* Copyright: Eugene Wissner 2016-2017. * Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
@ -14,13 +21,542 @@
*/ */
module tanya.math; module tanya.math;
public import tanya.math.mp; import tanya.math.mp;
public import tanya.math.random; import tanya.math.nbtheory;
import tanya.meta.trait; import tanya.meta.trait;
version (unittest) /// Floating-point number precisions according to IEEE-754.
enum IEEEPrecision : ubyte
{ {
import std.algorithm.iteration; single = 4, /// Single precision: 64-bit.
double_ = 8, /// Single precision: 64-bit.
doubleExtended = 10, /// Double extended precision: 80-bit.
}
/**
* Tests the precision of floating-point type $(D_PARAM F).
*
* For $(D_KEYWORD float), $(D_PSYMBOL ieeePrecision) always evaluates to
* $(D_INLINECODE IEEEPrecision.single); for $(D_KEYWORD double) - to
* $(D_INLINECODE IEEEPrecision.double). It returns different values only
* for $(D_KEYWORD real), since $(D_KEYWORD real) is a platform-dependent type.
*
* If $(D_PARAM F) is a $(D_KEYWORD real) and the target platform isn't
* currently supported, static assertion error will be raised (you can use
* $(D_INLINECODE is(typeof(ieeePrecision!F))) for testing the platform support
* without a compilation error).
*
* Params:
* F = Type to be tested.
*
* Returns: Precision according to IEEE-754.
*
* See_Also: $(D_PSYMBOL IEEEPrecision).
*/
template ieeePrecision(F)
if (isFloatingPoint!F)
{
static if (F.sizeof == float.sizeof)
{
enum IEEEPrecision ieeePrecision = IEEEPrecision.single;
}
else static if (F.sizeof == double.sizeof)
{
enum IEEEPrecision ieeePrecision = IEEEPrecision.double_;
}
else version (X86)
{
enum IEEEPrecision ieeePrecision = IEEEPrecision.doubleExtended;
}
else version (X86_64)
{
enum IEEEPrecision ieeePrecision = IEEEPrecision.doubleExtended;
}
else
{
static assert(false, "Unsupported IEEE 754 floating point precision");
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(ieeePrecision!float == IEEEPrecision.single);
static assert(ieeePrecision!double == IEEEPrecision.double_);
}
private union FloatBits(F)
{
F floating;
static if (ieeePrecision!F == IEEEPrecision.single)
{
uint integral;
enum uint expMask = 0x7f800000;
}
else static if (ieeePrecision!F == IEEEPrecision.double_)
{
ulong integral;
enum ulong expMask = 0x7ff0000000000000;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
struct // Little-endian.
{
ulong mantissa;
ushort exp;
}
enum ulong mantissaMask = 0x7fffffffffffffff;
enum uint expMask = 0x7fff;
}
else
{
static assert(false, "Unsupported IEEE 754 floating point precision");
}
}
/**
* Floating-point number classifications.
*/
enum FloatingPointClass : ubyte
{
/**
* Not a Number.
*
* See_Also: $(D_PSYMBOL isNaN).
*/
nan,
/// Zero.
zero,
/**
* Infinity.
*
* See_Also: $(D_PSYMBOL isInfinity).
*/
infinite,
/**
* Denormalized number.
*
* See_Also: $(D_PSYMBOL isSubnormal).
*/
subnormal,
/**
* Normalized number.
*
* See_Also: $(D_PSYMBOL isNormal).
*/
normal,
}
/**
* Returns whether $(D_PARAM x) is a NaN, zero, infinity, subnormal or
* normalized number.
*
* This function doesn't distinguish between negative and positive infinity,
* negative and positive NaN or negative and positive zero.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: Classification of $(D_PARAM x).
*/
FloatingPointClass classify(F)(F x)
if (isFloatingPoint!F)
{
if (x == 0)
{
return FloatingPointClass.zero;
}
FloatBits!F bits;
bits.floating = abs(x);
static if (ieeePrecision!F == IEEEPrecision.single)
{
if (bits.integral > bits.expMask)
{
return FloatingPointClass.nan;
}
else if (bits.integral == bits.expMask)
{
return FloatingPointClass.infinite;
}
else if (bits.integral < (1 << 23))
{
return FloatingPointClass.subnormal;
}
}
else static if (ieeePrecision!F == IEEEPrecision.double_)
{
if (bits.integral > bits.expMask)
{
return FloatingPointClass.nan;
}
else if (bits.integral == bits.expMask)
{
return FloatingPointClass.infinite;
}
else if (bits.integral < (1L << 52))
{
return FloatingPointClass.subnormal;
}
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
if (bits.exp == bits.expMask)
{
if ((bits.mantissa & bits.mantissaMask) == 0)
{
return FloatingPointClass.infinite;
}
else
{
return FloatingPointClass.nan;
}
}
else if (bits.exp == 0)
{
return FloatingPointClass.subnormal;
}
else if (bits.mantissa < (1L << 63)) // "Unnormal".
{
return FloatingPointClass.nan;
}
}
return FloatingPointClass.normal;
}
///
pure nothrow @safe @nogc unittest
{
assert(classify(0.0) == FloatingPointClass.zero);
assert(classify(double.nan) == FloatingPointClass.nan);
assert(classify(double.infinity) == FloatingPointClass.infinite);
assert(classify(-double.infinity) == FloatingPointClass.infinite);
assert(classify(1.4) == FloatingPointClass.normal);
assert(classify(1.11254e-307 / 10) == FloatingPointClass.subnormal);
assert(classify(0.0f) == FloatingPointClass.zero);
assert(classify(float.nan) == FloatingPointClass.nan);
assert(classify(float.infinity) == FloatingPointClass.infinite);
assert(classify(-float.infinity) == FloatingPointClass.infinite);
assert(classify(0.3) == FloatingPointClass.normal);
assert(classify(5.87747e-38f / 10) == FloatingPointClass.subnormal);
assert(classify(0.0L) == FloatingPointClass.zero);
assert(classify(real.nan) == FloatingPointClass.nan);
assert(classify(real.infinity) == FloatingPointClass.infinite);
assert(classify(-real.infinity) == FloatingPointClass.infinite);
}
private pure nothrow @nogc @safe unittest
{
static if (ieeePrecision!float == IEEEPrecision.doubleExtended)
{
assert(classify(1.68105e-10) == FloatingPointClass.normal);
assert(classify(1.68105e-4932L) == FloatingPointClass.subnormal);
// Emulate unnormals, because they aren't generated anymore since i386
FloatBits!real unnormal;
unnormal.exp = 0x123;
unnormal.mantissa = 0x1;
assert(classify(unnormal) == FloatingPointClass.subnormal);
}
}
/**
* Determines whether $(D_PARAM x) is a finite number.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a finite number,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isInfinity).
*/
bool isFinite(F)(F x)
if (isFloatingPoint!F)
{
FloatBits!F bits;
static if (ieeePrecision!F == IEEEPrecision.single
|| ieeePrecision!F == IEEEPrecision.double_)
{
bits.floating = x;
bits.integral &= bits.expMask;
return bits.integral != bits.expMask;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
bits.floating = abs(x);
return (bits.exp != bits.expMask)
&& (bits.exp == 0 || bits.mantissa >= (1L << 63));
}
}
///
pure nothrow @safe @nogc unittest
{
assert(!isFinite(float.infinity));
assert(!isFinite(-double.infinity));
assert(isFinite(0.0));
assert(!isFinite(float.nan));
assert(isFinite(5.87747e-38f / 10));
assert(isFinite(1.11254e-307 / 10));
assert(isFinite(0.5));
}
/**
* Determines whether $(D_PARAM x) is $(B n)ot $(B a) $(B n)umber (NaN).
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is not a number,
* $(D_KEYWORD false) otherwise.
*/
bool isNaN(F)(F x)
if (isFloatingPoint!F)
{
FloatBits!F bits;
bits.floating = abs(x);
static if (ieeePrecision!F == IEEEPrecision.single
|| ieeePrecision!F == IEEEPrecision.double_)
{
return bits.integral > bits.expMask;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
const maskedMantissa = bits.mantissa & bits.mantissaMask;
if ((bits.exp == bits.expMask && maskedMantissa != 0)
|| ((bits.exp != 0) && (bits.mantissa < (1L << 63))))
{
return true;
}
return false;
}
}
///
pure nothrow @safe @nogc unittest
{
assert(isNaN(float.init));
assert(isNaN(double.init));
assert(isNaN(real.init));
}
/**
* Determines whether $(D_PARAM x) is a positive or negative infinity.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is infinity, $(D_KEYWORD false)
* otherwise.
*
* See_Also: $(D_PSYMBOL isFinite).
*/
bool isInfinity(F)(F x)
if (isFloatingPoint!F)
{
FloatBits!F bits;
bits.floating = abs(x);
static if (ieeePrecision!F == IEEEPrecision.single
|| ieeePrecision!F == IEEEPrecision.double_)
{
return bits.integral == bits.expMask;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
return (bits.exp == bits.expMask)
&& ((bits.mantissa & bits.mantissaMask) == 0);
}
}
///
pure nothrow @safe @nogc unittest
{
assert(isInfinity(float.infinity));
assert(isInfinity(-float.infinity));
assert(isInfinity(double.infinity));
assert(isInfinity(-double.infinity));
assert(isInfinity(real.infinity));
assert(isInfinity(-real.infinity));
}
/**
* Determines whether $(D_PARAM x) is a denormilized number or not.
* Denormalized number is a number between `0` and `1` that cannot be
* represented as
*
* <pre>
* m*2<sup>e</sup>
* </pre>
*
* where $(I m) is the mantissa and $(I e) is an exponent that fits into the
* exponent field of the type $(D_PARAM F).
*
* `0` is neither normalized nor denormalized.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a denormilized number,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isNormal).
*/
bool isSubnormal(F)(F x)
if (isFloatingPoint!F)
{
FloatBits!F bits;
bits.floating = abs(x);
static if (ieeePrecision!F == IEEEPrecision.single)
{
return bits.integral < (1 << 23) && bits.integral > 0;
}
else static if (ieeePrecision!F == IEEEPrecision.double_)
{
return bits.integral < (1L << 52) && bits.integral > 0;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
return bits.exp == 0 && bits.mantissa != 0;
}
}
///
pure nothrow @safe @nogc unittest
{
assert(!isSubnormal(0.0f));
assert(!isSubnormal(float.nan));
assert(!isSubnormal(float.infinity));
assert(!isSubnormal(0.3f));
assert(isSubnormal(5.87747e-38f / 10));
assert(!isSubnormal(0.0));
assert(!isSubnormal(double.nan));
assert(!isSubnormal(double.infinity));
assert(!isSubnormal(1.4));
assert(isSubnormal(1.11254e-307 / 10));
assert(!isSubnormal(0.0L));
assert(!isSubnormal(real.nan));
assert(!isSubnormal(real.infinity));
}
/**
* Determines whether $(D_PARAM x) is a normilized number or not.
* Normalized number is a number that can be represented as
*
* <pre>
* m*2<sup>e</sup>
* </pre>
*
* where $(I m) is the mantissa and $(I e) is an exponent that fits into the
* exponent field of the type $(D_PARAM F).
*
* `0` is neither normalized nor denormalized.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a normilized number,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isSubnormal).
*/
bool isNormal(F)(F x)
if (isFloatingPoint!F)
{
static if (ieeePrecision!F == IEEEPrecision.single
|| ieeePrecision!F == IEEEPrecision.double_)
{
FloatBits!F bits;
bits.floating = x;
bits.integral &= bits.expMask;
return bits.integral != 0 && bits.integral != bits.expMask;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
return classify(x) == FloatingPointClass.normal;
}
}
///
pure nothrow @safe @nogc unittest
{
assert(!isNormal(0.0f));
assert(!isNormal(float.nan));
assert(!isNormal(float.infinity));
assert(isNormal(0.3f));
assert(!isNormal(5.87747e-38f / 10));
assert(!isNormal(0.0));
assert(!isNormal(double.nan));
assert(!isNormal(double.infinity));
assert(isNormal(1.4));
assert(!isNormal(1.11254e-307 / 10));
assert(!isNormal(0.0L));
assert(!isNormal(real.nan));
assert(!isNormal(real.infinity));
}
/**
* Determines whether the sign bit of $(D_PARAM x) is set or not.
*
* If the sign bit, $(D_PARAM x) is a negative number, otherwise positive.
*
* Params:
* F = Type of the floating point number.
* x = Floating point number.
*
* Returns: $(D_KEYWORD true) if the sign bit of $(D_PARAM x) is set,
* $(D_KEYWORD false) otherwise.
*/
bool signBit(F)(F x)
if (isFloatingPoint!F)
{
FloatBits!F bits;
bits.floating = x;
static if (ieeePrecision!F == IEEEPrecision.single)
{
return (bits.integral & (1 << 31)) != 0;
}
else static if (ieeePrecision!F == IEEEPrecision.double_)
{
return (bits.integral & (1L << 63)) != 0;
}
else static if (ieeePrecision!F == IEEEPrecision.doubleExtended)
{
return (bits.exp & (1 << 15)) != 0;
}
}
///
pure nothrow @safe @nogc unittest
{
assert(signBit(-1.0f));
assert(!signBit(1.0f));
assert(signBit(-1.0));
assert(!signBit(1.0));
assert(signBit(-1.0L));
assert(!signBit(1.0L));
} }
/** /**
@ -82,7 +618,7 @@ body
return result; return result;
} }
/// Ditto. /// ditto
I pow(I)(const auto ref I x, const auto ref I y, const auto ref I z) I pow(I)(const auto ref I x, const auto ref I y, const auto ref I z)
if (is(I == Integer)) if (is(I == Integer))
in in
@ -137,7 +673,7 @@ pure nothrow @safe @nogc unittest
} }
/// ///
unittest nothrow @safe @nogc unittest
{ {
assert(pow(Integer(3), Integer(5), Integer(7)) == 5); assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
assert(pow(Integer(2), Integer(2), Integer(1)) == 0); assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
@ -165,41 +701,40 @@ bool isPseudoprime(ulong x) nothrow pure @safe @nogc
} }
/// ///
unittest pure nothrow @safe @nogc unittest
{ {
uint[30] known = [74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, assert(74623.isPseudoprime);
74843, 74747, 74759, 74761, 74771, 74779, 74797, 74821, assert(104729.isPseudoprime);
74827, 9973, 104729, 15485867, 49979693, 104395303, assert(15485867.isPseudoprime);
593441861, 104729, 15485867, 49979693, 104395303, assert(!15485868.isPseudoprime);
593441861, 899809363, 982451653];
known.each!((ref x) => assert(isPseudoprime(x)));
} }
/** private pure nothrow @safe @nogc unittest
* Params:
* I = Value type.
* x = Value.
*
* Returns: The absolute value of a number.
*/
I abs(I : Integer)(const auto ref I x)
{ {
auto result = Integer(x, x.allocator); assert(74653.isPseudoprime);
result.sign = Sign.positive; assert(74687.isPseudoprime);
return result; assert(74699.isPseudoprime);
} assert(74707.isPseudoprime);
assert(74713.isPseudoprime);
/// Ditto. assert(74717.isPseudoprime);
I abs(I : Integer)(I x) assert(74719.isPseudoprime);
{ assert(74747.isPseudoprime);
x.sign = Sign.positive; assert(74759.isPseudoprime);
return x; assert(74761.isPseudoprime);
} assert(74771.isPseudoprime);
assert(74779.isPseudoprime);
/// Ditto. assert(74797.isPseudoprime);
I abs(I)(const I x) assert(74821.isPseudoprime);
if (isIntegral!I) assert(74827.isPseudoprime);
{ assert(9973.isPseudoprime);
return x >= 0 ? x : -x; assert(49979693.isPseudoprime);
assert(104395303.isPseudoprime);
assert(593441861.isPseudoprime);
assert(104729.isPseudoprime);
assert(15485867.isPseudoprime);
assert(49979693.isPseudoprime);
assert(104395303.isPseudoprime);
assert(593441861.isPseudoprime);
assert(899809363.isPseudoprime);
assert(982451653.isPseudoprime);
} }

View File

@ -227,8 +227,9 @@ class Entropy
* See_Also: * See_Also:
* $(D_PSYMBOL EntropySource) * $(D_PSYMBOL EntropySource)
*/ */
Entropy opOpAssign(string Op)(EntropySource source) pure nothrow @safe @nogc Entropy opOpAssign(string op)(EntropySource source)
if (Op == "~") pure nothrow @safe @nogc
if (op == "~")
in in
{ {
assert(sourceCount_ <= sources.length); assert(sourceCount_ <= sources.length);
@ -299,7 +300,7 @@ class Entropy
// Perform second SHA-512 on entropy // Perform second SHA-512 on entropy
output = sha512Of(output); output = sha512Of(output);
for (ubyte i = 0; i < sourceCount; ++i) for (ubyte i; i < sourceCount; ++i)
{ {
sources[i].size = 0; sources[i].size = 0;
} }

View File

@ -1,441 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implementions of functions found in $(D_PSYMBOL tanya.memory.op) for x64.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/arch/x86_64.d,
* tanya/memory/arch/x86_64.d)
*/
module tanya.memory.arch.x86_64;
import tanya.memory.op;
version (D_InlineAsm_X86_64):
pragma(inline, true)
package (tanya.memory) void copy(const void[] source, void[] target)
pure nothrow @system @nogc
{
asm pure nothrow @nogc
{
naked;
// RDI and RSI should be preserved.
mov RAX, RDI;
mov R8, RSI;
}
// Set the registers for movsb/movsq.
version (Windows) asm pure nothrow @nogc
{
// RDX - source.
// RCX - target.
mov RDI, [ RCX + 8 ];
mov RSI, [ RDX + 8 ];
mov RDX, [ RDX ];
}
else asm pure nothrow @nogc
{
// RDX - source length.
// RCX - source data.
// RDI - target length
// RSI - target data.
mov RDI, RSI;
mov RSI, RCX;
}
asm pure nothrow @nogc
{
cmp RDX, 0x08;
jc aligned_1;
test EDI, 0x07;
jz aligned_8;
naligned:
movsb;
dec RDX;
test EDI, 0x07;
jnz naligned;
aligned_8:
mov RCX, RDX;
shr RCX, 0x03;
rep;
movsq;
and EDX, 0x07;
jz end;
aligned_1:
// Write the remaining bytes.
mov RCX, RDX;
rep;
movsb;
end: // Restore registers.
mov RSI, R8;
mov RDI, RAX;
ret;
}
}
package (tanya.memory) template fill(ubyte Byte)
{
private enum const(char[]) MovArrayPointer(string Destination)()
{
string asmCode = "asm pure nothrow @nogc { mov ";
version (Windows)
{
asmCode ~= Destination ~ ", [ RCX + 8 ];";
}
else
{
asmCode ~= Destination ~ ", RSI;";
}
return asmCode ~ "}";
}
pragma(inline, true)
void fill(void[] memory)
{
asm pure nothrow @nogc
{
naked;
}
version (Windows) asm pure nothrow @nogc
{
/*
* RCX - array.
*/
mov R8, [ RCX ];
}
else asm pure nothrow @nogc
{
/*
* RSI - pointer.
* RDI - length.
*/
mov R8, RDI;
}
mixin(MovArrayPointer!"R9");
asm pure nothrow @nogc
{
// Check for zero length.
test R8, R8;
jz end;
}
// Set 128- and 64-bit registers to values we want to fill with.
static if (Byte == 0)
{
asm pure nothrow @nogc
{
xor RAX, RAX;
pxor XMM0, XMM0;
}
}
else
{
enum ulong FilledBytes = FilledBytes!Byte;
asm pure nothrow @nogc
{
mov RAX, FilledBytes;
movq XMM0, RAX;
movlhps XMM0, XMM0;
}
}
asm pure nothrow @nogc
{
// Check if the pointer is aligned to a 16-byte boundary.
and R9, -0x10;
}
// Compute the number of misaligned bytes.
mixin(MovArrayPointer!"R10");
asm pure nothrow @nogc
{
sub R10, R9;
test R10, R10;
jz aligned;
// Get the number of bytes to be written until we are aligned.
mov RDX, 0x10;
sub RDX, R10;
}
mixin(MovArrayPointer!"R9");
asm pure nothrow @nogc
{
naligned:
mov [ R9 ], AL; // Write a byte.
// Advance the pointer. Decrease the total number of bytes
// and the misaligned ones.
inc R9;
dec RDX;
dec R8;
// Checks if we are aligned.
test RDX, RDX;
jnz naligned;
aligned:
// Checks if we're done writing bytes.
test R8, R8;
jz end;
// Write 1 byte at a time.
cmp R8, 8;
jl aligned_1;
// Write 8 bytes at a time.
cmp R8, 16;
jl aligned_8;
// Write 16 bytes at a time.
cmp R8, 32;
jl aligned_16;
// Write 32 bytes at a time.
cmp R8, 64;
jl aligned_32;
aligned_64:
movdqa [ R9 ], XMM0;
movdqa [ R9 + 16 ], XMM0;
movdqa [ R9 + 32 ], XMM0;
movdqa [ R9 + 48 ], XMM0;
add R9, 64;
sub R8, 64;
cmp R8, 64;
jge aligned_64;
// Checks if we're done writing bytes.
test R8, R8;
jz end;
// Write 1 byte at a time.
cmp R8, 8;
jl aligned_1;
// Write 8 bytes at a time.
cmp R8, 16;
jl aligned_8;
// Write 16 bytes at a time.
cmp R8, 32;
jl aligned_16;
aligned_32:
movdqa [ R9 ], XMM0;
movdqa [ R9 + 16 ], XMM0;
add R9, 32;
sub R8, 32;
// Checks if we're done writing bytes.
test R8, R8;
jz end;
// Write 1 byte at a time.
cmp R8, 8;
jl aligned_1;
// Write 8 bytes at a time.
cmp R8, 16;
jl aligned_8;
aligned_16:
movdqa [ R9 ], XMM0;
add R9, 16;
sub R8, 16;
// Checks if we're done writing bytes.
test R8, R8;
jz end;
// Write 1 byte at a time.
cmp R8, 8;
jl aligned_1;
aligned_8:
mov [ R9 ], RAX;
add R9, 8;
sub R8, 8;
// Checks if we're done writing bytes.
test R8, R8;
jz end;
aligned_1:
mov [ R9 ], AL;
inc R9;
dec R8;
test R8, R8;
jnz aligned_1;
end:
ret;
}
}
}
pragma(inline, true)
package (tanya.memory) void copyBackward(const void[] source, void[] target)
pure nothrow @system @nogc
{
asm pure nothrow @nogc
{
naked;
// Save the registers should be restored.
mov R8, RSI;
mov R9, RDI;
}
// Prepare the registers for movsb.
version (Windows) asm pure nothrow @nogc
{
// RDX - source.
// RCX - target.
mov RAX, [ RCX + 8 ];
mov R10, [ RDX + 8 ];
mov RCX, [ RDX ];
lea RDI, [ RAX + RCX - 1 ];
lea RSI, [ R10 + RCX - 1 ];
}
else asm pure nothrow @nogc
{
// RDX - source length.
// RCX - source data.
// RDI - target length
// RSI - target data.
lea RDI, [ RSI + RDX - 1 ];
lea RSI, [ RCX + RDX - 1 ];
mov RCX, RDX;
}
asm pure nothrow @nogc
{
std; // Set the direction flag.
rep;
movsb;
cld; // Clear the direction flag.
// Restore registers.
mov RDI, R9;
mov RSI, R8;
ret;
}
}
pragma(inline, true)
package (tanya.memory) int cmp(const void[] r1, const void[] r2)
pure nothrow @system @nogc
{
asm pure nothrow @nogc
{
naked;
// RDI and RSI should be preserved.
mov R9, RDI;
mov R8, RSI;
}
// Set the registers for cmpsb/cmpsq.
version (Windows) asm pure nothrow @nogc
{
// RDX - r1.
// RCX - r2.
mov RDI, [ RCX + 8 ];
mov RSI, [ RDX + 8 ];
mov RDX, [ RDX ];
mov RCX, [ RCX ];
}
else asm pure nothrow @nogc
{
// RDX - r1 length.
// RCX - r1 data.
// RDI - r2 length
// RSI - r2 data.
mov RSI, RCX;
mov RCX, RDI;
mov RDI, R8;
}
asm pure nothrow @nogc
{
// Compare the lengths.
cmp RDX, RCX;
jl less;
jg greater;
// Check if we're aligned.
cmp RDX, 0x08;
jc aligned_1;
test EDI, 0x07;
jz aligned_8;
naligned:
cmpsb;
jl less;
jg greater;
dec RDX;
test EDI, 0x07;
jnz naligned;
aligned_8:
mov RCX, RDX;
shr RCX, 0x03;
repe;
cmpsq;
jl less;
jg greater;
and EDX, 0x07;
jz equal;
aligned_1: // Compare the remaining bytes.
mov RCX, RDX;
repe;
cmpsb;
jl less;
jg greater;
equal:
xor RAX, RAX; // Return 0.
jmp end;
greater:
mov RAX, 1;
jmp end;
less:
mov RAX, -1;
jmp end;
end: // Restore registers.
mov RSI, R8;
mov RDI, R9;
ret;
}
}

View File

@ -14,14 +14,17 @@
*/ */
module tanya.memory.mmappool; module tanya.memory.mmappool;
import core.stdc.string;
import std.algorithm.comparison; import std.algorithm.comparison;
import tanya.memory.allocator; import tanya.memory.allocator;
import tanya.memory.op;
version (Posix) version (Posix)
{ {
import core.sys.posix.sys.mman : PROT_READ, PROT_WRITE, MAP_PRIVATE, import core.sys.posix.sys.mman : MAP_ANON,
MAP_ANON, MAP_FAILED; MAP_FAILED,
MAP_PRIVATE,
PROT_READ,
PROT_WRITE;
import core.sys.posix.unistd; import core.sys.posix.unistd;
extern(C) extern(C)
@ -89,6 +92,7 @@ else version (Windows)
* block as free and only if all blocks in the region are free, the complete * block as free and only if all blocks in the region are free, the complete
* region is deallocated. * region is deallocated.
* *
* <pre>
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* | | | | | || | | | * | | | | | || | | |
* | |prev <----------- | || | | | * | |prev <----------- | || | | |
@ -100,6 +104,7 @@ else version (Windows)
* | N | -----------> next| || N | | | * | N | -----------> next| || N | | |
* | | | | | || | | | * | | | | | || | | |
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* </pre>
*/ */
final class MmapPool : Allocator final class MmapPool : Allocator
{ {
@ -345,10 +350,10 @@ final class MmapPool : Allocator
|| dataSize < size || dataSize < size
|| block1.next.size + BlockEntry.sizeof < delta) || block1.next.size + BlockEntry.sizeof < delta)
{ {
/* * It is the last block in the region /* - It is the last block in the region
* * The next block is too small * - The next block isn't free
* * The next block isn't free * - The next block is too small
* * Requested size is too large * - Requested size is too large
*/ */
return false; return false;
} }
@ -363,8 +368,8 @@ final class MmapPool : Allocator
{ {
block1.next.next.prev = block2; block1.next.next.prev = block2;
} }
// block1.next and block2 can overlap. copyBackward((cast(void*) block1.next)[0 .. BlockEntry.sizeof],
memmove(cast(void*) block2, cast(void*) block1.next, BlockEntry.sizeof); (cast(void*) block2)[0 .. BlockEntry.sizeof]);
block1.next = block2; block1.next = block2;
} }
else else
@ -436,7 +441,7 @@ final class MmapPool : Allocator
} }
if (p !is null) if (p !is null)
{ {
memcpy(reallocP.ptr, p.ptr, min(p.length, size)); copy(p[0 .. min(p.length, size)], reallocP);
deallocate(p); deallocate(p);
} }
p = reallocP; p = reallocP;
@ -500,7 +505,7 @@ final class MmapPool : Allocator
void* data = initializeRegion(instanceSize, head, pageSize); void* data = initializeRegion(instanceSize, head, pageSize);
if (data !is null) if (data !is null)
{ {
memcpy(data, typeid(MmapPool).initializer.ptr, instanceSize); copy(typeid(MmapPool).initializer, data[0 .. instanceSize]);
instance_ = cast(shared MmapPool) data; instance_ = cast(shared MmapPool) data;
instance_.head = head; instance_.head = head;
instance_.pageSize = pageSize; instance_.pageSize = pageSize;

View File

@ -14,9 +14,22 @@
*/ */
module tanya.memory.op; module tanya.memory.op;
version (D_InlineAsm_X86_64) version (TanyaNative)
{ {
static import tanya.memory.arch.x86_64; extern private void fillMemory(void[], size_t) pure nothrow @system @nogc;
extern private void copyMemory(const void[], void[])
pure nothrow @system @nogc;
extern private void moveMemory(const void[], void[])
pure nothrow @system @nogc;
extern private int cmpMemory(const void[], const void[])
pure nothrow @system @nogc;
}
else
{
import core.stdc.string;
} }
private enum alignMask = size_t.sizeof - 1; private enum alignMask = size_t.sizeof - 1;
@ -45,46 +58,13 @@ in
} }
body body
{ {
version (D_InlineAsm_X86_64) version (TanyaNative)
{ {
tanya.memory.arch.x86_64.copy(source, target); copyMemory(source, target);
} }
else // Naive implementation. else
{ {
auto source1 = cast(const(ubyte)*) source; memcpy(target.ptr, source.ptr, source.length);
auto target1 = cast(ubyte*) target;
auto count = source.length;
// Check if the pointers are aligned or at least can be aligned
// properly.
ushort naligned = (cast(size_t) source.ptr) & alignMask;
if (naligned == ((cast(size_t) target.ptr) & alignMask))
{
// Align the pointers if possible.
if (naligned != 0)
{
count -= naligned;
while (naligned--)
{
*target1++ = *source1++;
}
}
// Copy size_t.sizeof bytes at once.
auto longSource = cast(const(size_t)*) source1;
auto longTarget = cast(size_t*) target1;
for (; count >= size_t.sizeof; count -= size_t.sizeof)
{
*longTarget++ = *longSource++;
}
// Adjust the original pointers.
source1 = cast(const(ubyte)*) longSource;
target1 = cast(ubyte*) longTarget;
}
// Copy the remaining bytes by one.
while (count--)
{
*target1++ = *source1++;
}
} }
} }
@ -120,58 +100,34 @@ private pure nothrow @safe @nogc unittest
/* /*
* size_t value each of which bytes is set to `Byte`. * size_t value each of which bytes is set to `Byte`.
*/ */
package template FilledBytes(ubyte Byte, ubyte I = 0) private template filledBytes(ubyte Byte, ubyte I = 0)
{ {
static if (I == size_t.sizeof) static if (I == size_t.sizeof)
{ {
enum size_t FilledBytes = Byte; enum size_t filledBytes = Byte;
} }
else else
{ {
enum size_t FilledBytes = (FilledBytes!(Byte, I + 1) << 8) | Byte; enum size_t filledBytes = (filledBytes!(Byte, I + 1) << 8) | Byte;
} }
} }
/** /**
* Fills $(D_PARAM memory) with single $(D_PARAM Byte)s. * Fills $(D_PARAM memory) with the single byte $(D_PARAM c).
* *
* Param: * Param:
* Byte = The value to fill $(D_PARAM memory) with. * c = The value to fill $(D_PARAM memory) with.
* memory = Memory block. * memory = Memory block.
*/ */
void fill(ubyte Byte = 0)(void[] memory) @trusted void fill(ubyte c = 0)(void[] memory) @trusted
{ {
version (D_InlineAsm_X86_64) version (TanyaNative)
{ {
tanya.memory.arch.x86_64.fill!Byte(memory); fillMemory(memory, filledBytes!c);
} }
else // Naive implementation. else
{ {
auto n = memory.length; memset(memory.ptr, c, memory.length);
ubyte* vp = cast(ubyte*) memory.ptr;
// Align.
while (((cast(size_t) vp) & alignMask) != 0)
{
*vp++ = Byte;
--n;
}
// Set size_t.sizeof bytes at ones.
auto sp = cast(size_t*) vp;
while (n / size_t.sizeof > 0)
{
*sp++ = FilledBytes!Byte;
n -= size_t.sizeof;
}
// Write the remaining bytes.
vp = cast(ubyte*) sp;
while (n--)
{
*vp = Byte;
++vp;
}
} }
} }
@ -240,41 +196,13 @@ in
} }
body body
{ {
version (D_InlineAsm_X86_64) version (TanyaNative)
{ {
tanya.memory.arch.x86_64.copyBackward(source, target); moveMemory(source, target);
} }
else // Naive implementation. else
{ {
auto count = source.length; memmove(target.ptr, source.ptr, source.length);
// Try to align the pointers if possible.
if (((cast(size_t) source.ptr) & alignMask) == ((cast(size_t) target.ptr) & alignMask))
{
while (((cast(size_t) (source.ptr + count)) & alignMask) != 0)
{
if (!count--)
{
return;
}
(cast(ubyte[]) target)[count]
= (cast(const(ubyte)[]) source)[count];
}
}
// Write as long we're aligned.
for (; count >= size_t.sizeof; count -= size_t.sizeof)
{
*(cast(size_t*) (target.ptr + count - size_t.sizeof))
= *(cast(const(size_t)*) (source.ptr + count - size_t.sizeof));
}
// Write the remaining bytes.
while (count--)
{
(cast(ubyte[]) target)[count]
= (cast(const(ubyte)[]) source)[count];
}
} }
} }
@ -316,60 +244,17 @@ private nothrow @safe @nogc unittest
*/ */
int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc
{ {
version (D_InlineAsm_X86_64) version (TanyaNative)
{ {
return tanya.memory.arch.x86_64.cmp(r1, r2); return cmpMemory(r1, r2);
} }
else // Naive implementation. else
{ {
if (r1.length > r2.length) if (r1.length > r2.length)
{ {
return 1; return 1;
} }
else if (r1.length < r2.length) return r1.length < r2.length ? -1 : memcmp(r1.ptr, r2.ptr, r1.length);
{
return -1;
}
auto p1 = cast(const(ubyte)*) r1;
auto p2 = cast(const(ubyte)*) r2;
auto count = r1.length;
// Check if the pointers are aligned or at least can be aligned
// properly.
if (((cast(size_t) p1) & alignMask) == ((cast(size_t) p2) & alignMask))
{
// Align the pointers if possible.
for (; ((cast(size_t) p1) & alignMask) != 0; ++p1, ++p2, --count)
{
if (*p1 != *p2)
{
return *p1 - *p2;
}
}
// Compare size_t.sizeof bytes at once.
for (; count >= size_t.sizeof; count -= size_t.sizeof)
{
if (*(cast(const(size_t)*) p1) > *(cast(const(size_t)*) p2))
{
return 1;
}
else if (*(cast(const(size_t)*) p1) < *(cast(const(size_t)*) p2))
{
return -1;
}
p1 += size_t.sizeof;
p2 += size_t.sizeof;
}
}
// Compare the remaining bytes by one.
for (; count--; ++p1, ++p2)
{
if (*p1 != *p2)
{
return *p1 - *p2;
}
}
return 0;
} }
} }
@ -402,3 +287,79 @@ private pure nothrow @safe @nogc unittest
assert(cmp(r1[0 .. $ - 1], r2[0 .. $ - 1]) == 0); assert(cmp(r1[0 .. $ - 1], r2[0 .. $ - 1]) == 0);
assert(cmp(r1[0 .. 8], r2[0 .. 8]) == 0); assert(cmp(r1[0 .. 8], r2[0 .. 8]) == 0);
} }
/**
* Finds the first occurrence of $(D_PARAM needle) in $(D_PARAM haystack) if
* any.
*
* Params:
* haystack = Memory block.
* needle = A byte.
*
* Returns: The subrange of $(D_PARAM haystack) whose first element is the
* first occurrence of $(D_PARAM needle). If $(D_PARAM needle)
* couldn't be found, an empty `inout void[]` is returned.
*/
inout(void[]) find(return inout void[] haystack, const ubyte needle)
pure nothrow @trusted @nogc
{
auto length = haystack.length;
const size_t needleWord = size_t.max * needle;
enum size_t highBits = filledBytes!(0x01, 0);
enum size_t mask = filledBytes!(0x80, 0);
// Align
auto bytes = cast(inout(ubyte)*) haystack;
while (length > 0 && ((cast(size_t) bytes) & 3) != 0)
{
if (*bytes == needle)
{
return bytes[0 .. length];
}
bytes++;
length--;
}
// Check if some of the words has the needle
auto words = cast(inout(size_t)*) bytes;
while (length >= size_t.sizeof)
{
if (((*words ^ needleWord) - highBits) & (~*words) & mask)
{
break;
}
words++;
length -= size_t.sizeof;
}
// Find the exact needle position in the word
bytes = cast(inout(ubyte)*) words;
while (length > 0)
{
if (*bytes == needle)
{
return bytes[0 .. length];
}
bytes++;
length--;
}
return haystack[$ .. $];
}
///
pure nothrow @safe @nogc unittest
{
const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
assert(find(haystack, 'a') == haystack[]);
assert(find(haystack, 'b') == haystack[1 .. $]);
assert(find(haystack, 'c') == haystack[2 .. $]);
assert(find(haystack, 'd') == haystack[3 .. $]);
assert(find(haystack, 'e') == haystack[4 .. $]);
assert(find(haystack, 'f') == haystack[5 .. $]);
assert(find(haystack, 'h') == haystack[8 .. $]);
assert(find(haystack, 'i').length == 0);
assert(find(null, 'a').length == 0);
}

View File

@ -14,14 +14,14 @@
*/ */
module tanya.memory; module tanya.memory;
import core.exception;
import std.algorithm.iteration; import std.algorithm.iteration;
import std.algorithm.mutation; import std.algorithm.mutation;
import std.conv; import tanya.conv;
import std.range; import tanya.exception;
public import tanya.memory.allocator; public import tanya.memory.allocator;
import tanya.memory.mmappool; import tanya.memory.mmappool;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.range.primitive;
/** /**
* The mixin generates common methods for classes and structs using * The mixin generates common methods for classes and structs using
@ -72,7 +72,7 @@ mixin template DefaultAllocator()
return allocator_; return allocator_;
} }
/// Ditto. /// ditto
@property shared(Allocator) allocator() const pure nothrow @trusted @nogc @property shared(Allocator) allocator() const pure nothrow @trusted @nogc
out (allocator) out (allocator)
{ {
@ -141,21 +141,54 @@ body
* Returns the size in bytes of the state that needs to be allocated to hold an * Returns the size in bytes of the state that needs to be allocated to hold an
* object of type $(D_PARAM T). * object of type $(D_PARAM T).
* *
* There is a difference between the `.sizeof`-property and
* $(D_PSYMBOL stateSize) if $(D_PARAM T) is a class or an interface.
* `T.sizeof` is constant on the given architecture then and is the same as
* `size_t.sizeof` and `ptrdiff_t.sizeof`. This is because classes and
* interfaces are reference types and `.sizeof` returns the size of the
* reference which is the same as the size of a pointer. $(D_PSYMBOL stateSize)
* returns the size of the instance itself.
*
* The size of a dynamic array is `size_t.sizeof * 2` since a dynamic array
* stores its length and a data pointer. The size of the static arrays is
* calculated differently since they are value types. It is the array length
* multiplied by the element size.
*
* `stateSize!void` is `1` since $(D_KEYWORD void) is mostly used as a synonym
* for $(D_KEYWORD byte)/$(D_KEYWORD ubyte) in `void*`.
*
* Params: * Params:
* T = Object type. * T = Object type.
*
* Returns: Size of an instance of type $(D_PARAM T).
*/ */
template stateSize(T) template stateSize(T)
{ {
static if (is(T == class) || is(T == interface)) static if (isPolymorphicType!T)
{ {
enum stateSize = __traits(classInstanceSize, T); enum size_t stateSize = __traits(classInstanceSize, T);
} }
else else
{ {
enum stateSize = T.sizeof; enum size_t stateSize = T.sizeof;
} }
} }
///
@nogc nothrow pure @safe unittest
{
static assert(stateSize!int == 4);
static assert(stateSize!bool == 1);
static assert(stateSize!(int[]) == (size_t.sizeof * 2));
static assert(stateSize!(short[3]) == 6);
static struct Empty
{
}
static assert(stateSize!Empty == 1);
static assert(stateSize!void == 1);
}
/** /**
* Params: * Params:
* size = Raw size. * size = Raw size.
@ -196,14 +229,14 @@ package(tanya) T[] resize(T)(shared Allocator allocator,
} }
else else
{ {
onOutOfMemoryErrorNoGC(); onOutOfMemoryError();
} }
} }
void[] buf = array; void[] buf = array;
if (!allocator.reallocate(buf, length * T.sizeof)) if (!allocator.reallocate(buf, length * T.sizeof))
{ {
onOutOfMemoryErrorNoGC(); onOutOfMemoryError();
} }
// Casting from void[] is unsafe, but we know we cast to the original type. // Casting from void[] is unsafe, but we know we cast to the original type.
array = cast(T[]) buf; array = cast(T[]) buf;
@ -420,9 +453,7 @@ body
{ {
() @trusted { allocator.deallocate(mem); }(); () @trusted { allocator.deallocate(mem); }();
} }
return emplace!T(mem[0 .. stateSize!T], args);
auto ptr = (() @trusted => (cast(T*) mem[0 .. stateSize!T].ptr))();
return emplace!T(ptr, args);
} }
/// ///

View File

@ -6,7 +6,13 @@
* Smart pointers. * Smart pointers.
* *
* A smart pointer is an object that wraps a raw pointer or a reference * A smart pointer is an object that wraps a raw pointer or a reference
* (class, array) to manage its lifetime. * (class, dynamic array) to manage its lifetime.
*
* This module provides two kinds of lifetime management strategies:
* $(UL
* $(LI Reference counting)
* $(LI Unique ownership)
* )
* *
* Copyright: Eugene Wissner 2016-2017. * Copyright: Eugene Wissner 2016-2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
@ -17,17 +23,17 @@
*/ */
module tanya.memory.smartref; module tanya.memory.smartref;
import core.exception;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.mutation; import std.algorithm.mutation;
import std.conv; import tanya.conv;
import std.range; import tanya.exception;
import tanya.memory; import tanya.memory;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.range.primitive;
private template Payload(T) private template Payload(T)
{ {
static if (is(T == class) || is(T == interface) || isArray!T) static if (isPolymorphicType!T || isArray!T)
{ {
alias Payload = T; alias Payload = T;
} }
@ -127,7 +133,7 @@ struct RefCounted(T)
this.storage.payload = value; this.storage.payload = value;
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -202,14 +208,7 @@ struct RefCounted(T)
return this; return this;
} }
private @nogc unittest /// ditto
{
auto rc = defaultAllocator.refCounted!int(5);
rc = defaultAllocator.make!int(7);
assert(*rc == 7);
}
/// Ditto.
ref typeof(this) opAssign(typeof(null)) ref typeof(this) opAssign(typeof(null))
{ {
if (this.storage is null) if (this.storage is null)
@ -229,15 +228,7 @@ struct RefCounted(T)
return this; return this;
} }
private @nogc unittest /// ditto
{
RefCounted!int rc;
assert(!rc.isInitialized);
rc = null;
assert(!rc.isInitialized);
}
/// Ditto.
ref typeof(this) opAssign(typeof(this) rhs) ref typeof(this) opAssign(typeof(this) rhs)
{ {
swap(this.allocator_, rhs.allocator_); swap(this.allocator_, rhs.allocator_);
@ -308,7 +299,7 @@ struct RefCounted(T)
} }
/// ///
unittest @nogc @system unittest
{ {
auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator); auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator);
auto val = rc.get(); auto val = rc.get();
@ -324,7 +315,22 @@ unittest
assert(*rc.storage.payload == 9); assert(*rc.storage.payload == 9);
} }
private @nogc unittest @nogc @system unittest
{
auto rc = defaultAllocator.refCounted!int(5);
rc = defaultAllocator.make!int(7);
assert(*rc == 7);
}
@nogc @system unittest
{
RefCounted!int rc;
assert(!rc.isInitialized);
rc = null;
assert(!rc.isInitialized);
}
@nogc @system unittest
{ {
auto rc = defaultAllocator.refCounted!int(5); auto rc = defaultAllocator.refCounted!int(5);
@ -340,7 +346,7 @@ private @nogc unittest
assert(*rc == 5); assert(*rc == 5);
} }
private @nogc unittest @nogc @system unittest
{ {
RefCounted!int rc; RefCounted!int rc;
@ -355,7 +361,7 @@ private @nogc unittest
assert(rc.count == 0); assert(rc.count == 0);
} }
private unittest @nogc @system unittest
{ {
RefCounted!int rc1, rc2; RefCounted!int rc1, rc2;
static assert(is(typeof(rc1 = rc2))); static assert(is(typeof(rc1 = rc2)));
@ -389,7 +395,7 @@ version (unittest)
} }
} }
private @nogc unittest @nogc @system unittest
{ {
uint destroyed; uint destroyed;
auto a = defaultAllocator.make!A(destroyed); auto a = defaultAllocator.make!A(destroyed);
@ -399,7 +405,7 @@ private @nogc unittest
auto rc = RefCounted!A(a, defaultAllocator); auto rc = RefCounted!A(a, defaultAllocator);
assert(rc.count == 1); assert(rc.count == 1);
void func(RefCounted!A rc) @nogc void func(RefCounted!A rc) @nogc @system
{ {
assert(rc.count == 2); assert(rc.count == 2);
} }
@ -415,14 +421,14 @@ private @nogc unittest
assert(rc.count == 1); assert(rc.count == 1);
} }
private @nogc unittest @nogc @system unittest
{ {
auto rc = RefCounted!int(defaultAllocator); auto rc = RefCounted!int(defaultAllocator);
assert(!rc.isInitialized); assert(!rc.isInitialized);
assert(rc.allocator is defaultAllocator); assert(rc.allocator is defaultAllocator);
} }
private @nogc unittest @nogc @system unittest
{ {
auto rc = defaultAllocator.refCounted!int(5); auto rc = defaultAllocator.refCounted!int(5);
assert(rc.count == 1); assert(rc.count == 1);
@ -444,7 +450,7 @@ private @nogc unittest
assert(rc.count == 0); assert(rc.count == 0);
} }
private unittest @nogc @system unittest
{ {
auto rc = defaultAllocator.refCounted!int(5); auto rc = defaultAllocator.refCounted!int(5);
assert(*rc == 5); assert(*rc == 5);
@ -460,7 +466,7 @@ private unittest
assert(*rc == 5); assert(*rc == 5);
} }
private unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(typeof(RefCounted!int.storage.payload) == int*)); static assert(is(typeof(RefCounted!int.storage.payload) == int*));
static assert(is(typeof(RefCounted!A.storage.payload) == A)); static assert(is(typeof(RefCounted!A.storage.payload) == A));
@ -511,17 +517,9 @@ body
{ {
() @trusted { allocator.deallocate(mem); }(); () @trusted { allocator.deallocate(mem); }();
} }
rc.storage = emplace!((RefCounted!T.Storage))(mem[0 .. storageSize]); rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]);
static if (is(T == class))
{
rc.storage.payload = emplace!T(mem[storageSize .. $], args); rc.storage.payload = emplace!T(mem[storageSize .. $], args);
}
else
{
auto ptr = (() @trusted => (cast(T*) mem[storageSize .. $].ptr))();
rc.storage.payload = emplace!T(ptr, args);
}
rc.deleter = &unifiedDeleter!(Payload!T); rc.deleter = &unifiedDeleter!(Payload!T);
return rc; return rc;
} }
@ -554,7 +552,7 @@ body
} }
/// ///
unittest @nogc @system unittest
{ {
auto rc = defaultAllocator.refCounted!int(5); auto rc = defaultAllocator.refCounted!int(5);
assert(rc.count == 1); assert(rc.count == 1);
@ -575,7 +573,7 @@ unittest
assert(rc.count == 1); assert(rc.count == 1);
} }
private @nogc unittest @nogc @system unittest
{ {
struct E struct E
{ {
@ -597,13 +595,13 @@ private @nogc unittest
} }
} }
private @nogc unittest @nogc @system unittest
{ {
auto rc = defaultAllocator.refCounted!(int[])(5); auto rc = defaultAllocator.refCounted!(int[])(5);
assert(rc.length == 5); assert(rc.length == 5);
} }
private @nogc unittest @nogc @system unittest
{ {
auto p1 = defaultAllocator.make!int(5); auto p1 = defaultAllocator.make!int(5);
auto p2 = p1; auto p2 = p1;
@ -611,13 +609,13 @@ private @nogc unittest
assert(rc.get() is p2); assert(rc.get() is p2);
} }
private @nogc unittest @nogc @system unittest
{ {
static bool destroyed = false; static bool destroyed = false;
struct F static struct F
{ {
~this() @nogc ~this() @nogc nothrow @safe
{ {
destroyed = true; destroyed = true;
} }
@ -660,7 +658,7 @@ struct Unique(T)
this.payload = value; this.payload = value;
} }
/// Ditto. /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
{ {
@ -706,14 +704,14 @@ struct Unique(T)
return this; return this;
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(typeof(null)) ref typeof(this) opAssign(typeof(null))
{ {
allocator.dispose(this.payload); allocator.dispose(this.payload);
return this; return this;
} }
/// Ditto. /// ditto
ref typeof(this) opAssign(typeof(this) rhs) ref typeof(this) opAssign(typeof(this) rhs)
{ {
swap(this.allocator_, rhs.allocator_); swap(this.allocator_, rhs.allocator_);
@ -723,7 +721,7 @@ struct Unique(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @system unittest
{ {
auto rc = defaultAllocator.unique!int(5); auto rc = defaultAllocator.unique!int(5);
rc = defaultAllocator.make!int(7); rc = defaultAllocator.make!int(7);
@ -770,7 +768,7 @@ struct Unique(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @system unittest
{ {
Unique!int u; Unique!int u;
assert(!u.isInitialized); assert(!u.isInitialized);
@ -789,7 +787,7 @@ struct Unique(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @system unittest
{ {
auto u = defaultAllocator.unique!int(5); auto u = defaultAllocator.unique!int(5);
assert(u.isInitialized); assert(u.isInitialized);
@ -804,7 +802,7 @@ struct Unique(T)
} }
/// ///
@nogc unittest @nogc nothrow pure @system unittest
{ {
auto p = defaultAllocator.make!int(5); auto p = defaultAllocator.make!int(5);
auto s = Unique!int(p, defaultAllocator); auto s = Unique!int(p, defaultAllocator);
@ -812,13 +810,13 @@ struct Unique(T)
} }
/// ///
@nogc unittest @nogc nothrow @system unittest
{ {
static bool destroyed = false; static bool destroyed = false;
struct F static struct F
{ {
~this() @nogc ~this() @nogc nothrow @safe
{ {
destroyed = true; destroyed = true;
} }
@ -885,13 +883,13 @@ body
return Unique!T(payload, allocator); return Unique!T(payload, allocator);
} }
private unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(typeof(defaultAllocator.unique!B(5)))); static assert(is(typeof(defaultAllocator.unique!B(5))));
static assert(is(typeof(defaultAllocator.unique!(int[])(5)))); static assert(is(typeof(defaultAllocator.unique!(int[])(5))));
} }
private unittest @nogc nothrow pure @system unittest
{ {
auto s = defaultAllocator.unique!int(5); auto s = defaultAllocator.unique!int(5);
assert(*s == 5); assert(*s == 5);
@ -900,7 +898,7 @@ private unittest
assert(s is null); assert(s is null);
} }
private unittest @nogc nothrow pure @system unittest
{ {
auto s = defaultAllocator.unique!int(5); auto s = defaultAllocator.unique!int(5);
assert(*s == 5); assert(*s == 5);
@ -909,7 +907,7 @@ private unittest
assert(*s == 4); assert(*s == 4);
} }
private @nogc unittest @nogc nothrow pure @system unittest
{ {
auto p1 = defaultAllocator.make!int(5); auto p1 = defaultAllocator.make!int(5);
auto p2 = p1; auto p2 = p1;
@ -918,7 +916,7 @@ private @nogc unittest
assert(rc.get() is p2); assert(rc.get() is p2);
} }
private @nogc unittest @nogc nothrow pure @system unittest
{ {
auto rc = Unique!int(defaultAllocator); auto rc = Unique!int(defaultAllocator);
assert(rc.allocator is defaultAllocator); assert(rc.allocator is defaultAllocator);

View File

@ -19,6 +19,7 @@
module tanya.meta.metafunction; module tanya.meta.metafunction;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform;
/** /**
* Finds the minimum value in $(D_PARAM Args) according to $(D_PARAM pred). * Finds the minimum value in $(D_PARAM Args) according to $(D_PARAM pred).
@ -60,7 +61,7 @@ if (Args.length > 0 && isTemplate!pred)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool cmp(alias T, alias U) = T < U; enum bool cmp(alias T, alias U) = T < U;
static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3); static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3);
@ -107,7 +108,7 @@ if (Args.length > 0 && isTemplate!pred)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool cmp(alias T, alias U) = T < U; enum bool cmp(alias T, alias U) = T < U;
static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13); static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13);
@ -179,7 +180,7 @@ if (Tuples.length > 0
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias Result1 = ZipWith!(AliasSeq, alias Result1 = ZipWith!(AliasSeq,
Tuple!(1, 2), Tuple!(1, 2),
@ -241,7 +242,7 @@ template Tuple(Args...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias A = Tuple!(short); alias A = Tuple!(short);
alias B = Tuple!(3, 8, 9); alias B = Tuple!(3, 8, 9);
@ -279,7 +280,7 @@ template Set(Args...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias S1 = Set!(int, 5, 5, int, 4); alias S1 = Set!(int, 5, 5, int, 4);
static assert(S1.length == 3); static assert(S1.length == 3);
@ -314,7 +315,7 @@ if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias S1 = Set!(2, 5, 8, 4); alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1); alias S2 = Set!(3, 8, 4, 1);
@ -367,7 +368,7 @@ if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias S1 = Set!(2, 5, 8, 4); alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1); alias S2 = Set!(3, 8, 4, 1);
@ -414,7 +415,7 @@ if (isInstanceOf!(Set, S1) && isInstanceOf!(Set, S2))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias S1 = Set!(2, 5, 8, 4); alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1); alias S2 = Set!(3, 8, 4, 1);
@ -457,7 +458,7 @@ if (Args.length == 2 && isTemplate!cmp)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool boolCmp(T, U) = T.sizeof < U.sizeof; enum bool boolCmp(T, U) = T.sizeof < U.sizeof;
static assert(isLessEqual!(boolCmp, byte, int)); static assert(isLessEqual!(boolCmp, byte, int));
@ -504,7 +505,7 @@ if (Args.length == 2 && isTemplate!cmp)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool boolCmp(T, U) = T.sizeof < U.sizeof; enum bool boolCmp(T, U) = T.sizeof < U.sizeof;
static assert(!isGreaterEqual!(boolCmp, byte, int)); static assert(!isGreaterEqual!(boolCmp, byte, int));
@ -551,7 +552,7 @@ if (Args.length == 2 && isTemplate!cmp)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool boolCmp(T, U) = T.sizeof < U.sizeof; enum bool boolCmp(T, U) = T.sizeof < U.sizeof;
static assert(isLess!(boolCmp, byte, int)); static assert(isLess!(boolCmp, byte, int));
@ -598,7 +599,7 @@ if (Args.length == 2 && isTemplate!cmp)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum bool boolCmp(T, U) = T.sizeof < U.sizeof; enum bool boolCmp(T, U) = T.sizeof < U.sizeof;
static assert(!isGreater!(boolCmp, byte, int)); static assert(!isGreater!(boolCmp, byte, int));
@ -643,7 +644,7 @@ if (Args.length == 2)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isEqual!(int, int)); static assert(isEqual!(int, int));
static assert(isEqual!(8, 8)); static assert(isEqual!(8, 8));
@ -673,7 +674,7 @@ if (Args.length == 2)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(!isNotEqual!(int, int)); static assert(!isNotEqual!(int, int));
static assert(isNotEqual!(5, int)); static assert(isNotEqual!(5, int));
@ -692,7 +693,7 @@ pure nothrow @safe @nogc unittest
alias Instantiate(alias T, Args...) = T!Args; alias Instantiate(alias T, Args...) = T!Args;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
template Template(T) template Template(T)
{ {
@ -707,38 +708,6 @@ pure nothrow @safe @nogc unittest
static assert(is(Instance2 == float)); static assert(is(Instance2 == float));
} }
version (TanyaPhobos)
{
public import std.meta : Alias,
AliasSeq,
aliasSeqOf,
Erase,
EraseAll,
Filter,
NoDuplicates,
DerivedToFront,
MostDerived,
Repeat,
Replace,
ReplaceAll,
Reverse,
Map = staticMap,
Sort = staticSort,
allSatisfy,
anySatisfy,
staticIndexOf,
templateAnd,
templateNot,
templateOr,
isSorted = staticIsSorted,
ApplyLeft,
ApplyRight;
}
else:
import tanya.meta.trait;
import tanya.meta.transform;
/** /**
* Creates an alias for $(D_PARAM T). * Creates an alias for $(D_PARAM T).
* *
@ -765,11 +734,11 @@ import tanya.meta.transform;
*/ */
alias Alias(alias T) = T; alias Alias(alias T) = T;
/// Ditto. /// ditto
alias Alias(T) = T; alias Alias(T) = T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Alias!int)); static assert(is(Alias!int));
@ -800,7 +769,7 @@ pure nothrow @safe @nogc unittest
alias AliasSeq(Args...) = Args; alias AliasSeq(Args...) = Args;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(typeof({ alias T = AliasSeq!(short, 5); }))); static assert(is(typeof({ alias T = AliasSeq!(short, 5); })));
static assert(is(typeof({ alias T = AliasSeq!(int, short, 5); }))); static assert(is(typeof({ alias T = AliasSeq!(int, short, 5); })));
@ -848,7 +817,7 @@ if (isTemplate!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(allSatisfy!(isSigned, int, short, byte, long)); static assert(allSatisfy!(isSigned, int, short, byte, long));
static assert(!allSatisfy!(isUnsigned, uint, ushort, float, ulong)); static assert(!allSatisfy!(isUnsigned, uint, ushort, float, ulong));
@ -886,7 +855,7 @@ if (isTemplate!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(anySatisfy!(isSigned, int, short, byte, long)); static assert(anySatisfy!(isSigned, int, short, byte, long));
static assert(anySatisfy!(isUnsigned, uint, ushort, float, ulong)); static assert(anySatisfy!(isUnsigned, uint, ushort, float, ulong));
@ -916,8 +885,8 @@ if (Args.length > 0)
* `-1` is returned if $(D_PARAM T) is not found. * `-1` is returned if $(D_PARAM T) is not found.
* *
* Params: * Params:
* T = The type to search for. * T = The item to search for.
* L = Type list. * L = Symbol sequence.
* *
* Returns: The index of the first occurrence of $(D_PARAM T) in $(D_PARAM L). * Returns: The index of the first occurrence of $(D_PARAM T) in $(D_PARAM L).
*/ */
@ -926,14 +895,14 @@ template staticIndexOf(T, L...)
enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L)); enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L));
} }
/// Ditto. /// ditto
template staticIndexOf(alias T, L...) template staticIndexOf(alias T, L...)
{ {
enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L)); enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L));
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(staticIndexOf!(int) == -1); static assert(staticIndexOf!(int) == -1);
static assert(staticIndexOf!(int, int) == 0); static assert(staticIndexOf!(int, int) == 0);
@ -941,6 +910,37 @@ pure nothrow @safe @nogc unittest
static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3); static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3);
} }
/**
* Looks for $(D_PARAM T) in $(D_PARAM L) and returns $(D_KEYWORD true) if it
* could be found and $(D_KEYWORD false) otherwise.
*
* Params:
* T = The item to search for.
* L = Symbol sequence.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) can be found in $(D_PARAM L),
* $(D_KEYWORD false) otherwise.
*/
template canFind(T, L...)
{
enum bool canFind = indexOf!(0, AliasSeq!(T, L)) != -1;
}
/// ditto
template canFind(alias T, L...)
{
enum bool canFind = indexOf!(0, AliasSeq!(T, L)) != -1;
}
///
@nogc nothrow pure @safe unittest
{
static assert(!canFind!(int));
static assert(canFind!(int, int));
static assert(canFind!(int, float, double, int, real));
static assert(canFind!(3, () {}, uint, 5, 3));
}
/** /**
* Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd) * Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd)
* evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on. * evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on.
@ -973,7 +973,7 @@ if (allSatisfy!(isTemplate, Preds))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias isMutableInt = templateAnd!(isIntegral, isMutable); alias isMutableInt = templateAnd!(isIntegral, isMutable);
static assert(isMutableInt!int); static assert(isMutableInt!int);
@ -1021,7 +1021,7 @@ if (allSatisfy!(isTemplate, Preds))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias isMutableOrInt = templateOr!(isIntegral, isMutable); alias isMutableOrInt = templateOr!(isIntegral, isMutable);
static assert(isMutableOrInt!int); static assert(isMutableOrInt!int);
@ -1051,7 +1051,7 @@ if (isTemplate!pred)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias isNotIntegral = templateNot!isIntegral; alias isNotIntegral = templateNot!isIntegral;
static assert(!isNotIntegral!int); static assert(!isNotIntegral!int);
@ -1094,11 +1094,8 @@ if (isTemplate!cmp)
} }
} }
deprecated("Use tanya.meta.metafunction.isSorted instead")
alias staticIsSorted = isSorted;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum cmp(T, U) = T.sizeof < U.sizeof; enum cmp(T, U) = T.sizeof < U.sizeof;
static assert(isSorted!(cmp)); static assert(isSorted!(cmp));
@ -1107,7 +1104,7 @@ pure nothrow @safe @nogc unittest
static assert(!isSorted!(cmp, long, byte, ubyte, short, uint)); static assert(!isSorted!(cmp, long, byte, ubyte, short, uint));
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum cmp(int x, int y) = x - y; enum cmp(int x, int y) = x - y;
static assert(isSorted!(cmp)); static assert(isSorted!(cmp));
@ -1119,7 +1116,7 @@ private pure nothrow @safe @nogc unittest
static assert(isSorted!(cmp, 32, 32)); static assert(isSorted!(cmp, 32, 32));
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum cmp(int x, int y) = x < y; enum cmp(int x, int y) = x < y;
static assert(isSorted!(cmp)); static assert(isSorted!(cmp));
@ -1145,7 +1142,7 @@ template ApplyLeft(alias T, Args...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias allAreIntegral = ApplyLeft!(allSatisfy, isIntegral); alias allAreIntegral = ApplyLeft!(allSatisfy, isIntegral);
static assert(allAreIntegral!(int, uint)); static assert(allAreIntegral!(int, uint));
@ -1166,7 +1163,7 @@ template ApplyRight(alias T, Args...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias intIs = ApplyRight!(allSatisfy, int); alias intIs = ApplyRight!(allSatisfy, int);
static assert(intIs!(isIntegral)); static assert(intIs!(isIntegral));
@ -1194,7 +1191,7 @@ if (n > 0)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Repeat!(1, uint, int) == AliasSeq!(uint, int))); static assert(is(Repeat!(1, uint, int) == AliasSeq!(uint, int)));
static assert(is(Repeat!(2, uint, int) == AliasSeq!(uint, int, uint, int))); static assert(is(Repeat!(2, uint, int) == AliasSeq!(uint, int, uint, int)));
@ -1233,26 +1230,26 @@ template Replace(T, U, L...)
alias Replace = ReplaceOne!(T, U, L); alias Replace = ReplaceOne!(T, U, L);
} }
/// Ditto. /// ditto
template Replace(alias T, U, L...) template Replace(alias T, U, L...)
{ {
alias Replace = ReplaceOne!(T, U, L); alias Replace = ReplaceOne!(T, U, L);
} }
/// Ditto. /// ditto
template Replace(T, alias U, L...) template Replace(T, alias U, L...)
{ {
alias Replace = ReplaceOne!(T, U, L); alias Replace = ReplaceOne!(T, U, L);
} }
/// Ditto. /// ditto
template Replace(alias T, alias U, L...) template Replace(alias T, alias U, L...)
{ {
alias Replace = ReplaceOne!(T, U, L); alias Replace = ReplaceOne!(T, U, L);
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Replace!(int, uint, int) == AliasSeq!(uint))); static assert(is(Replace!(int, uint, int) == AliasSeq!(uint)));
static assert(is(Replace!(int, uint, short, int, int, ushort) static assert(is(Replace!(int, uint, short, int, int, ushort)
@ -1296,26 +1293,26 @@ template ReplaceAll(T, U, L...)
alias ReplaceAll = ReplaceAllImpl!(T, U, L); alias ReplaceAll = ReplaceAllImpl!(T, U, L);
} }
/// Ditto. /// ditto
template ReplaceAll(alias T, U, L...) template ReplaceAll(alias T, U, L...)
{ {
alias ReplaceAll = ReplaceAllImpl!(T, U, L); alias ReplaceAll = ReplaceAllImpl!(T, U, L);
} }
/// Ditto. /// ditto
template ReplaceAll(T, alias U, L...) template ReplaceAll(T, alias U, L...)
{ {
alias ReplaceAll = ReplaceAllImpl!(T, U, L); alias ReplaceAll = ReplaceAllImpl!(T, U, L);
} }
/// Ditto. /// ditto
template ReplaceAll(alias T, alias U, L...) template ReplaceAll(alias T, alias U, L...)
{ {
alias ReplaceAll = ReplaceAllImpl!(T, U, L); alias ReplaceAll = ReplaceAllImpl!(T, U, L);
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(ReplaceAll!(int, uint, int) == AliasSeq!(uint))); static assert(is(ReplaceAll!(int, uint, int) == AliasSeq!(uint)));
static assert(is(ReplaceAll!(int, uint, short, int, int, ushort) static assert(is(ReplaceAll!(int, uint, short, int, int, ushort)
@ -1343,7 +1340,7 @@ template Reverse(L...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Reverse!(byte, short, int) == AliasSeq!(int, short, byte))); static assert(is(Reverse!(byte, short, int) == AliasSeq!(int, short, byte)));
} }
@ -1371,7 +1368,7 @@ if (isTemplate!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Map!(Unqual, const int, immutable short) static assert(is(Map!(Unqual, const int, immutable short)
== AliasSeq!(int, short))); == AliasSeq!(int, short)));
@ -1432,14 +1429,14 @@ if (isTemplate!cmp)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum cmp(T, U) = T.sizeof < U.sizeof; enum cmp(T, U) = T.sizeof < U.sizeof;
static assert(is(Sort!(cmp, long, short, byte, int) static assert(is(Sort!(cmp, long, short, byte, int)
== AliasSeq!(byte, short, int, long))); == AliasSeq!(byte, short, int, long)));
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum cmp(int T, int U) = T - U; enum cmp(int T, int U) = T - U;
static assert(Sort!(cmp, 5, 17, 9, 12, 2, 10, 14) static assert(Sort!(cmp, 5, 17, 9, 12, 2, 10, 14)
@ -1463,7 +1460,7 @@ template DerivedToFront(L...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class A class A
{ {
@ -1504,7 +1501,7 @@ template MostDerived(T, L...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class A class A
{ {
@ -1550,14 +1547,14 @@ template Erase(T, L...)
alias Erase = EraseOne!(T, L); alias Erase = EraseOne!(T, L);
} }
/// Ditto. /// ditto
template Erase(alias T, L...) template Erase(alias T, L...)
{ {
alias Erase = EraseOne!(T, L); alias Erase = EraseOne!(T, L);
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Erase!(int, short, int, int, uint) == AliasSeq!(short, int, uint))); static assert(is(Erase!(int, short, int, int, uint) == AliasSeq!(short, int, uint)));
static assert(is(Erase!(int, short, uint) == AliasSeq!(short, uint))); static assert(is(Erase!(int, short, uint) == AliasSeq!(short, uint)));
@ -1593,14 +1590,14 @@ template EraseAll(T, L...)
alias EraseAll = EraseAllImpl!(T, L); alias EraseAll = EraseAllImpl!(T, L);
} }
/// Ditto. /// ditto
template EraseAll(alias T, L...) template EraseAll(alias T, L...)
{ {
alias EraseAll = EraseAllImpl!(T, L); alias EraseAll = EraseAllImpl!(T, L);
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(EraseAll!(int, short, int, int, uint) == AliasSeq!(short, uint))); static assert(is(EraseAll!(int, short, int, int, uint) == AliasSeq!(short, uint)));
static assert(is(EraseAll!(int, short, uint) == AliasSeq!(short, uint))); static assert(is(EraseAll!(int, short, uint) == AliasSeq!(short, uint)));
@ -1635,7 +1632,7 @@ template Filter(alias pred, L...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Filter!(isIntegral, real, int, bool, uint) == AliasSeq!(int, uint))); static assert(is(Filter!(isIntegral, real, int, bool, uint) == AliasSeq!(int, uint)));
} }
@ -1662,7 +1659,7 @@ template NoDuplicates(L...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias Types = AliasSeq!(int, uint, int, short, short, uint); alias Types = AliasSeq!(int, uint, int, short, short, uint);
static assert(is(NoDuplicates!Types == AliasSeq!(int, uint, short))); static assert(is(NoDuplicates!Types == AliasSeq!(int, uint, short)));
@ -1705,7 +1702,7 @@ template aliasSeqOf(alias range)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(aliasSeqOf!([0, 1, 2, 3]) == AliasSeq!(0, 1, 2, 3)); static assert(aliasSeqOf!([0, 1, 2, 3]) == AliasSeq!(0, 1, 2, 3));
} }
@ -1738,7 +1735,7 @@ if (n > 0)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(Stride!(3, 1, 2, 3, 4, 5, 6, 7, 8) == AliasSeq!(1, 4, 7)); static assert(Stride!(3, 1, 2, 3, 4, 5, 6, 7, 8) == AliasSeq!(1, 4, 7));
static assert(Stride!(2, 1, 2, 3) == AliasSeq!(1, 3)); static assert(Stride!(2, 1, 2, 3) == AliasSeq!(1, 3));
@ -1773,7 +1770,7 @@ if (T.length == 2)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Select!(true, int, float) == int)); static assert(is(Select!(true, int, float) == int));
static assert(is(Select!(false, int, float) == float)); static assert(is(Select!(false, int, float) == float));

View File

@ -45,7 +45,7 @@ import tanya.meta.transform;
enum bool isWideString(T) = is(T : const dchar[]) && !isStaticArray!T; enum bool isWideString(T) = is(T : const dchar[]) && !isStaticArray!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isWideString!(dchar[])); static assert(isWideString!(dchar[]));
static assert(!isWideString!(char[])); static assert(!isWideString!(char[]));
@ -101,7 +101,7 @@ if (Args.length >= 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Smallest!(int, ushort, uint, short) == ushort)); static assert(is(Smallest!(int, ushort, uint, short) == ushort));
static assert(is(Smallest!(short) == short)); static assert(is(Smallest!(short) == short));
@ -136,7 +136,7 @@ enum bool isComplex(T) = is(Unqual!(OriginalType!T) == cfloat)
|| is(Unqual!(OriginalType!T) == ireal); || is(Unqual!(OriginalType!T) == ireal);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isComplex!cfloat); static assert(isComplex!cfloat);
static assert(isComplex!ifloat); static assert(isComplex!ifloat);
@ -163,7 +163,7 @@ pure nothrow @safe @nogc unittest
enum bool isPOD(T) = __traits(isPOD, T); enum bool isPOD(T) = __traits(isPOD, T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S1 struct S1
{ {
@ -199,7 +199,7 @@ pure nothrow @safe @nogc unittest
enum size_t sizeOf(T) = T.sizeof; enum size_t sizeOf(T) = T.sizeof;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(sizeOf!(bool function()) == size_t.sizeof); static assert(sizeOf!(bool function()) == size_t.sizeof);
static assert(sizeOf!bool == 1); static assert(sizeOf!bool == 1);
@ -220,7 +220,7 @@ pure nothrow @safe @nogc unittest
enum size_t alignOf(T) = T.alignof; enum size_t alignOf(T) = T.alignof;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(alignOf!bool == bool.alignof); static assert(alignOf!bool == bool.alignof);
static assert(is(typeof(alignOf!bool) == typeof(bool.alignof))); static assert(is(typeof(alignOf!bool) == typeof(bool.alignof)));
@ -243,7 +243,7 @@ if (Args.length == 2)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isSame!("string", "string")); static assert(isSame!("string", "string"));
static assert(!isSame!(string, immutable(char)[])); static assert(!isSame!(string, immutable(char)[]));
@ -266,7 +266,7 @@ pure nothrow @safe @nogc unittest
enum bool isTemplate(alias T) = __traits(isTemplate, T); enum bool isTemplate(alias T) = __traits(isTemplate, T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S(T) struct S(T)
{ {
@ -275,38 +275,37 @@ pure nothrow @safe @nogc unittest
static assert(!isTemplate!(S!int)); static assert(!isTemplate!(S!int));
} }
/** deprecated("Use is(T == interface) instead")
* Determine whether $(D_PARAM T) is an interface.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface,
* $(D_KEYWORD false) otherwise.
*/
enum bool isInterface(T) = is(T == interface); enum bool isInterface(T) = is(T == interface);
/** deprecated("Use is(T == class) instead")
* Determine whether $(D_PARAM T) is a class.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a class
* $(D_KEYWORD false) otherwise.
*/
enum bool isClass(T) = is(T == class); enum bool isClass(T) = is(T == class);
deprecated("Use is(T == struct) instead")
enum bool isStruct(T) = is(T == struct);
/** /**
* Determine whether $(D_PARAM T) is a struct. * Determines whether $(D_PARAM T) is a polymorphic type, i.e. a
* $(D_KEYWORD class) or an $(D_KEYWORD interface).
* *
* Params: * Params:
* T = A type. * T = A type.
* *
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a struct, * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a $(D_KEYWORD class) or an
* $(D_KEYWORD false) otherwise. * $(D_KEYWORD interface), $(D_KEYWORD false) otherwise.
*/ */
enum bool isStruct(T) = is(T == struct); enum bool isPolymorphicType(T) = is(T == class) || is(T == interface);
///
@nogc nothrow pure @safe unittest
{
interface I
{
}
static assert(isPolymorphicType!Object);
static assert(isPolymorphicType!I);
static assert(!isPolymorphicType!short);
}
/** /**
* Params: * Params:
@ -339,7 +338,7 @@ template hasStaticMember(T, string member)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S struct S
{ {
@ -360,70 +359,6 @@ pure nothrow @safe @nogc unittest
static assert(hasStaticMember!(S, "member5")); static assert(hasStaticMember!(S, "member5"));
} }
version (TanyaPhobos)
{
public import std.traits : isFloatingPoint,
isSigned,
isUnsigned,
isIntegral,
isNumeric,
isBoolean,
isSomeChar,
isScalarType,
isBasicType,
isPointer,
isArray,
isStaticArray,
isDynamicArray,
isAssociativeArray,
isBuiltinType,
isAggregateType,
getUDAs,
isNarrowString,
isSomeString,
mostNegative,
Largest,
isCopyable,
isAbstractClass,
isFinalClass,
isAbstractFunction,
isFinalFunction,
isFunctionPointer,
isDelegate,
isFunction,
isSomeFunction,
isCallable,
hasMember,
isMutable,
isNested,
isNestedFunction,
mangledName,
isInstanceOf,
isImplicitlyConvertible,
BaseTypeTuple,
TransitiveBaseTypeTuple,
BaseClassesTuple,
InterfacesTuple,
isAssignable,
TemplateArgsOf,
Parameters,
ParameterIdentifierTuple,
functionAttributes,
ParameterDefaults,
hasElaborateDestructor,
hasElaborateCopyConstructor,
hasElaborateAssign,
EnumMembers,
classInstanceAlignment,
ifTestable,
FunctionTypeOf,
ReturnType,
TemplateOf,
isTypeTuple,
isExpressions;
}
else:
/** /**
* Determines whether $(D_PARAM T) is a floating point type. * Determines whether $(D_PARAM T) is a floating point type.
* *
@ -445,7 +380,7 @@ enum bool isFloatingPoint(T) = is(Unqual!(OriginalType!T) == double)
|| is(Unqual!(OriginalType!T) == real); || is(Unqual!(OriginalType!T) == real);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isFloatingPoint!float); static assert(isFloatingPoint!float);
static assert(isFloatingPoint!double); static assert(isFloatingPoint!double);
@ -485,7 +420,7 @@ enum bool isSigned(T) = is(Unqual!(OriginalType!T) == byte)
|| isFloatingPoint!T; || isFloatingPoint!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isSigned!byte); static assert(isSigned!byte);
static assert(isSigned!short); static assert(isSigned!short);
@ -526,7 +461,7 @@ enum bool isUnsigned(T) = is(Unqual!(OriginalType!T) == ubyte)
|| is(Unqual!(OriginalType!T) == ulong); || is(Unqual!(OriginalType!T) == ulong);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isUnsigned!ubyte); static assert(isUnsigned!ubyte);
static assert(isUnsigned!ushort); static assert(isUnsigned!ushort);
@ -570,7 +505,7 @@ enum bool isIntegral(T) = isUnsigned!T
|| is(Unqual!(OriginalType!T) == long); || is(Unqual!(OriginalType!T) == long);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isIntegral!ubyte); static assert(isIntegral!ubyte);
static assert(isIntegral!byte); static assert(isIntegral!byte);
@ -594,7 +529,7 @@ pure nothrow @safe @nogc unittest
enum bool isNumeric(T) = isIntegral!T || isFloatingPoint!T || isComplex!T; enum bool isNumeric(T) = isIntegral!T || isFloatingPoint!T || isComplex!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias F = float; alias F = float;
static assert(isNumeric!F); static assert(isNumeric!F);
@ -615,7 +550,7 @@ pure nothrow @safe @nogc unittest
enum bool isBoolean(T) = is(Unqual!(OriginalType!T) == bool); enum bool isBoolean(T) = is(Unqual!(OriginalType!T) == bool);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isBoolean!bool); static assert(isBoolean!bool);
static assert(isBoolean!(shared const bool)); static assert(isBoolean!(shared const bool));
@ -668,7 +603,7 @@ enum bool isSomeChar(T) = is(Unqual!(OriginalType!T) == char)
|| is(Unqual!(OriginalType!T) == dchar); || is(Unqual!(OriginalType!T) == dchar);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isSomeChar!char); static assert(isSomeChar!char);
static assert(isSomeChar!wchar); static assert(isSomeChar!wchar);
@ -700,7 +635,7 @@ pure nothrow @safe @nogc unittest
enum bool isScalarType(T) = isNumeric!T || isBoolean!T || isSomeChar!T; enum bool isScalarType(T) = isNumeric!T || isBoolean!T || isSomeChar!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isScalarType!int); static assert(isScalarType!int);
static assert(!isScalarType!(int[])); static assert(!isScalarType!(int[]));
@ -722,10 +657,14 @@ pure nothrow @safe @nogc unittest
enum bool isBasicType(T) = isScalarType!T || is(T : void); enum bool isBasicType(T) = isScalarType!T || is(T : void);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S; static struct S
class C; {
}
class C
{
}
enum E : int enum E : int
{ {
i = 0, i = 0,
@ -761,7 +700,7 @@ template isPointer(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isPointer!(bool*)); static assert(isPointer!(bool*));
static assert(isPointer!(const bool*)); static assert(isPointer!(const bool*));
@ -794,7 +733,7 @@ template isArray(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isArray!(bool[])); static assert(isArray!(bool[]));
static assert(isArray!(const bool[])); static assert(isArray!(const bool[]));
@ -828,7 +767,7 @@ template isStaticArray(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isStaticArray!(bool[8])); static assert(isStaticArray!(bool[8]));
static assert(isStaticArray!(const bool[8])); static assert(isStaticArray!(const bool[8]));
@ -852,7 +791,7 @@ pure nothrow @safe @nogc unittest
enum bool isDynamicArray(T) = isArray!T && !isStaticArray!T; enum bool isDynamicArray(T) = isArray!T && !isStaticArray!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isDynamicArray!(bool[])); static assert(isDynamicArray!(bool[]));
static assert(isDynamicArray!(const bool[])); static assert(isDynamicArray!(const bool[]));
@ -886,7 +825,7 @@ template isAssociativeArray(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isAssociativeArray!(bool[string])); static assert(isAssociativeArray!(bool[string]));
static assert(isAssociativeArray!(const bool[string])); static assert(isAssociativeArray!(const bool[string]));
@ -916,7 +855,7 @@ enum bool isBuiltinType(T) = isBasicType!T
|| isAssociativeArray!T; || isAssociativeArray!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isBuiltinType!int); static assert(isBuiltinType!int);
static assert(isBuiltinType!(int[])); static assert(isBuiltinType!(int[]));
@ -948,7 +887,7 @@ enum bool isAggregateType(T) = is(T == struct)
|| is(T == union); || is(T == union);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S; struct S;
class C; class C;
@ -964,41 +903,6 @@ pure nothrow @safe @nogc unittest
static assert(!isAggregateType!void); static assert(!isAggregateType!void);
} }
/**
* Determines whether $(D_PARAM T) is some type.
*
* Params:
* T = A symbol.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a type,
* $(D_KEYWORD false) otherwise.
*/
deprecated("Use isTypeTuple instead")
enum bool isType(alias T) = is(T);
/// Ditto.
deprecated("Use isTypeTuple instead")
enum bool isType(T) = true;
///
pure nothrow @safe @nogc unittest
{
class C;
enum E : bool;
union U;
struct T();
static assert(isType!C);
static assert(isType!E);
static assert(isType!U);
static assert(isType!void);
static assert(isType!int);
static assert(!isType!T);
static assert(isType!(T!()));
static assert(!isType!5);
static assert(!isType!(tanya.meta.trait));
}
/** /**
* Determines whether $(D_PARAM T) is a narrow string, i.e. consists of * Determines whether $(D_PARAM T) is a narrow string, i.e. consists of
* $(D_KEYWORD char) or $(D_KEYWORD wchar). * $(D_KEYWORD char) or $(D_KEYWORD wchar).
@ -1025,7 +929,7 @@ enum bool isNarrowString(T) = (is(T : const char[]) || is (T : const wchar[]))
&& !isStaticArray!T; && !isStaticArray!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isNarrowString!(char[])); static assert(isNarrowString!(char[]));
static assert(isNarrowString!(wchar[])); static assert(isNarrowString!(wchar[]));
@ -1074,7 +978,7 @@ pure nothrow @safe @nogc unittest
enum bool isSomeString(T) = isNarrowString!T || isWideString!T; enum bool isSomeString(T) = isNarrowString!T || isWideString!T;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isSomeString!(dchar[])); static assert(isSomeString!(dchar[]));
static assert(isSomeString!(char[])); static assert(isSomeString!(char[]));
@ -1132,7 +1036,7 @@ template mostNegative(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(mostNegative!char == char.min); static assert(mostNegative!char == char.min);
static assert(mostNegative!wchar == wchar.min); static assert(mostNegative!wchar == wchar.min);
@ -1181,7 +1085,7 @@ if (Args.length >= 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Largest!(int, short, uint) == int)); static assert(is(Largest!(int, short, uint) == int));
static assert(is(Largest!(short) == short)); static assert(is(Largest!(short) == short));
@ -1205,7 +1109,7 @@ pure nothrow @safe @nogc unittest
enum bool isCopyable(T) = is(typeof({ T s1 = T.init; T s2 = s1; })); enum bool isCopyable(T) = is(typeof({ T s1 = T.init; T s2 = s1; }));
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S1 struct S1
{ {
@ -1254,7 +1158,7 @@ pure nothrow @safe @nogc unittest
enum bool isAbstractClass(T) = __traits(isAbstractClass, T); enum bool isAbstractClass(T) = __traits(isAbstractClass, T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class A class A
{ {
@ -1282,6 +1186,9 @@ pure nothrow @safe @nogc unittest
static assert(!isAbstractClass!E); static assert(!isAbstractClass!E);
} }
private enum bool isType(alias T) = is(T);
private enum bool isType(T) = true;
/** /**
* Determines whether $(D_PARAM Args) contains only types. * Determines whether $(D_PARAM Args) contains only types.
* *
@ -1294,12 +1201,37 @@ pure nothrow @safe @nogc unittest
enum bool isTypeTuple(Args...) = allSatisfy!(isType, Args); enum bool isTypeTuple(Args...) = allSatisfy!(isType, Args);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isTypeTuple!(int, uint, Object)); static assert(isTypeTuple!(int, uint, Object));
static assert(isTypeTuple!()); static assert(isTypeTuple!());
static assert(!isTypeTuple!(int, 8, Object)); static assert(!isTypeTuple!(int, 8, Object));
static assert(!isTypeTuple!(5, 8, 2)); static assert(!isTypeTuple!(5, 8, 2));
class C
{
}
enum E : bool
{
t,
f,
}
union U
{
}
struct T()
{
}
static assert(isTypeTuple!C);
static assert(isTypeTuple!E);
static assert(isTypeTuple!U);
static assert(isTypeTuple!void);
static assert(isTypeTuple!int);
static assert(!isTypeTuple!T);
static assert(isTypeTuple!(T!()));
static assert(!isTypeTuple!5);
static assert(!isTypeTuple!(tanya.meta.trait));
} }
/** /**
@ -1342,7 +1274,7 @@ template isExpressions(Args...)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isExpressions!(5, 8, 2)); static assert(isExpressions!(5, 8, 2));
static assert(isExpressions!()); static assert(isExpressions!());
@ -1369,7 +1301,7 @@ pure nothrow @safe @nogc unittest
enum bool isFinalClass(T) = __traits(isFinalClass, T); enum bool isFinalClass(T) = __traits(isFinalClass, T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
final class A final class A
{ {
@ -1396,7 +1328,7 @@ pure nothrow @safe @nogc unittest
enum bool isAbstractFunction(alias F) = __traits(isAbstractFunction, F); enum bool isAbstractFunction(alias F) = __traits(isAbstractFunction, F);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class A class A
{ {
@ -1433,7 +1365,7 @@ pure nothrow @safe @nogc unittest
enum bool isFinalFunction(alias F) = __traits(isFinalFunction, F); enum bool isFinalFunction(alias F) = __traits(isFinalFunction, F);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class A class A
{ {
@ -1481,7 +1413,7 @@ if (F.length == 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isFunctionPointer!(void function())); static assert(isFunctionPointer!(void function()));
static assert(!isFunctionPointer!(void delegate())); static assert(!isFunctionPointer!(void delegate()));
@ -1538,7 +1470,7 @@ if (F.length == 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isDelegate!(void delegate())); static assert(isDelegate!(void delegate()));
static assert(!isDelegate!(void function())); static assert(!isDelegate!(void function()));
@ -1599,7 +1531,7 @@ if (F.length == 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(!isFunction!(void function())); static assert(!isFunction!(void function()));
static assert(!isFunction!(() {})); static assert(!isFunction!(() {}));
@ -1648,7 +1580,7 @@ if (F.length == 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isSomeFunction!(void function())); static assert(isSomeFunction!(void function()));
static assert(isSomeFunction!(() {})); static assert(isSomeFunction!(() {}));
@ -1695,7 +1627,7 @@ if (F.length == 1)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S struct S
{ {
@ -1720,7 +1652,7 @@ pure nothrow @safe @nogc unittest
static assert(!isCallable!I); static assert(!isCallable!I);
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S struct S
{ {
@ -1745,7 +1677,7 @@ private pure nothrow @safe @nogc unittest
enum bool hasMember(T, string member) = __traits(hasMember, T, member); enum bool hasMember(T, string member) = __traits(hasMember, T, member);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S struct S
{ {
@ -1800,7 +1732,7 @@ template isMutable(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S struct S
{ {
@ -1865,7 +1797,7 @@ pure nothrow @safe unittest
enum bool isNestedFunction(alias F) = __traits(isNested, F); enum bool isNestedFunction(alias F) = __traits(isNested, F);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
void func() void func()
{ {
@ -1902,13 +1834,13 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(FunctionTypeOf!(void function()) == function)); static assert(is(FunctionTypeOf!(void function()) == function));
static assert(is(FunctionTypeOf!(() {}) == function)); static assert(is(FunctionTypeOf!(() {}) == function));
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(FunctionTypeOf!(void delegate()) == function)); static assert(is(FunctionTypeOf!(void delegate()) == function));
@ -1951,7 +1883,7 @@ private pure nothrow @safe @nogc unittest
static assert(is(FunctionTypeOf!S == function)); static assert(is(FunctionTypeOf!S == function));
} }
private pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S2 struct S2
{ {
@ -1985,7 +1917,7 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(ReturnType!(int delegate()) == int)); static assert(is(ReturnType!(int delegate()) == int));
static assert(is(ReturnType!(bool function()) == bool)); static assert(is(ReturnType!(bool function()) == bool));
@ -2002,7 +1934,7 @@ pure nothrow @safe @nogc unittest
alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base; alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S(T) struct S(T)
{ {
@ -2058,7 +1990,7 @@ template isInstanceOf(alias T, alias I)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S(T) struct S(T)
{ {
@ -2088,7 +2020,7 @@ pure nothrow @safe @nogc unittest
enum bool isImplicitlyConvertible(From, To) = is(From : To); enum bool isImplicitlyConvertible(From, To) = is(From : To);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(isImplicitlyConvertible!(const(byte), byte)); static assert(isImplicitlyConvertible!(const(byte), byte));
static assert(isImplicitlyConvertible!(byte, char)); static assert(isImplicitlyConvertible!(byte, char));
@ -2124,7 +2056,7 @@ if (is(T == class) || (is(T == interface)))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
interface I1 interface I1
{ {
@ -2181,7 +2113,7 @@ if (is(T == class) || is(T == interface))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
interface I1 interface I1
{ {
@ -2231,7 +2163,7 @@ if (is(T == class))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
interface I1 interface I1
{ {
@ -2267,7 +2199,7 @@ if (is(T == class) || is(T == interface))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
interface I1 interface I1
{ {
@ -2317,7 +2249,7 @@ template isAssignable(Lhs, Rhs = Lhs)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S1 struct S1
{ {
@ -2358,7 +2290,7 @@ pure nothrow @safe @nogc unittest
alias TemplateArgsOf(alias T : Base!Args, alias Base, Args...) = Args; alias TemplateArgsOf(alias T : Base!Args, alias Base, Args...) = Args;
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
template T(A, B) template T(A, B)
{ {
@ -2388,7 +2320,7 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
int func(Object, uint[]); int func(Object, uint[]);
static assert(is(Parameters!func == AliasSeq!(Object, uint[]))); static assert(is(Parameters!func == AliasSeq!(Object, uint[])));
@ -2409,7 +2341,7 @@ if (isCallable!F)
{ {
static if (is(FunctionTypeOf!F Params == __parameters)) static if (is(FunctionTypeOf!F Params == __parameters))
{ {
enum string[] Impl() string[] Impl()
{ {
string[] tuple; string[] tuple;
@ -2436,7 +2368,7 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
int func(ref Object stuff, uint[] = null, scope uint k = 1); int func(ref Object stuff, uint[] = null, scope uint k = 1);
alias P = ParameterIdentifierTuple!func; alias P = ParameterIdentifierTuple!func;
@ -2480,7 +2412,7 @@ enum FunctionAttribute : uint
template functionAttributes(F...) template functionAttributes(F...)
if (isCallable!F) if (isCallable!F)
{ {
enum uint Impl() uint Impl()
{ {
uint attrs = FunctionAttribute.none; uint attrs = FunctionAttribute.none;
foreach (a; __traits(getFunctionAttributes, F[0])) foreach (a; __traits(getFunctionAttributes, F[0]))
@ -2548,7 +2480,7 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
@property ref int func1() pure nothrow @safe @nogc shared scope; @property ref int func1() pure nothrow @safe @nogc shared scope;
static assert((functionAttributes!func1 & FunctionAttribute.pure_) static assert((functionAttributes!func1 & FunctionAttribute.pure_)
@ -2616,7 +2548,7 @@ if (isCallable!F)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
void func1(int k, uint b = 5, int[] = [1, 2]); void func1(int k, uint b = 5, int[] = [1, 2]);
alias Defaults = ParameterDefaults!func1; alias Defaults = ParameterDefaults!func1;
@ -2655,7 +2587,7 @@ template hasElaborateDestructor(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class C class C
{ {
@ -2721,7 +2653,7 @@ template hasElaborateCopyConstructor(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(!hasElaborateCopyConstructor!int); static assert(!hasElaborateCopyConstructor!int);
@ -2783,7 +2715,7 @@ template hasElaborateAssign(T)
} }
} }
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(!hasElaborateAssign!int); static assert(!hasElaborateAssign!int);
@ -2883,7 +2815,7 @@ if (is(T == class))
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
class C1 class C1
{ {
@ -2926,7 +2858,7 @@ template ifTestable(T, alias pred = a => a)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(ifTestable!int); static assert(ifTestable!int);
@ -2982,7 +2914,7 @@ template getUDAs(alias symbol, alias attr)
{ {
alias FindUDA = AliasSeq!(); alias FindUDA = AliasSeq!();
} }
else static if ((isType!attr && is(TypeOf!(T[0]) == attr)) else static if ((isTypeTuple!attr && is(TypeOf!(T[0]) == attr))
|| (is(typeof(T[0] == attr)) && (T[0] == attr)) || (is(typeof(T[0] == attr)) && (T[0] == attr))
|| isInstanceOf!(attr, TypeOf!(T[0]))) || isInstanceOf!(attr, TypeOf!(T[0])))
{ {
@ -3000,7 +2932,7 @@ template getUDAs(alias symbol, alias attr)
alias getUDAs(alias symbol) = AliasSeq!(__traits(getAttributes, symbol)); alias getUDAs(alias symbol) = AliasSeq!(__traits(getAttributes, symbol));
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct Attr struct Attr
{ {
@ -3055,7 +2987,7 @@ template hasUDA(alias symbol, alias attr)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct Attr1 struct Attr1
{ {
@ -3067,3 +2999,59 @@ pure nothrow @safe @nogc unittest
static assert(hasUDA!(a, Attr1)); static assert(hasUDA!(a, Attr1));
static assert(!hasUDA!(a, Attr2)); static assert(!hasUDA!(a, Attr2));
} }
/**
* Tests whether $(D_PARAM T) is an inner class, i.e. a class nested inside
* another class.
*
* All inner classes get `outer` propery automatically generated, which points
* to its parent class, though it can be explicitly defined to be something
* different. If $(D_PARAM T) does this, $(D_PSYMBOL isInnerClass)
* evaluates to $(D_KEYWORD false).
*
* Params:
* T = Class to be tested.
*
* Returns $(D_KEYWORD true) if $(D_PARAM T) is an inner class,
* $(D_KEYWORD false) otherwise.
*/
template isInnerClass(T)
{
static if (is(T == class) && is(typeof(T.outer) == class))
{
enum bool isInnerClass = !canFind!("outer", __traits(allMembers, T));
}
else
{
enum bool isInnerClass = false;
}
}
///
@nogc nothrow pure @safe unittest
{
class A
{
}
class O
{
class I
{
}
class Fake
{
bool outer;
}
}
static assert(!isInnerClass!(O));
static assert(isInnerClass!(O.I));
static assert(!isInnerClass!(O.Fake));
}
@nogc nothrow pure @safe unittest
{
class RefCountedStore(T)
{
}
static assert(!isInnerClass!(RefCountedStore!int));
}

View File

@ -18,28 +18,6 @@
*/ */
module tanya.meta.transform; module tanya.meta.transform;
version (TanyaPhobos)
{
public import std.traits : Unqual,
OriginalType,
CopyConstness,
CopyTypeQualifiers,
Unsigned,
Signed,
PointerTarget,
KeyType,
ValueType,
Promoted,
InoutOf,
ConstOf,
SharedOf,
SharedInoutOf,
SharedConstOf,
ImmutableOf,
QualifierOf;
}
else:
import tanya.meta.trait; import tanya.meta.trait;
/** /**
@ -82,7 +60,7 @@ template Unqual(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Unqual!bool == bool)); static assert(is(Unqual!bool == bool));
static assert(is(Unqual!(immutable bool) == bool)); static assert(is(Unqual!(immutable bool) == bool));
@ -117,7 +95,7 @@ template OriginalType(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
enum E1 : const(int) enum E1 : const(int)
{ {
@ -188,7 +166,7 @@ template CopyConstness(From, To)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(CopyConstness!(int, char) == char)); static assert(is(CopyConstness!(int, char) == char));
static assert(is(CopyConstness!(const int, char) == const char)); static assert(is(CopyConstness!(const int, char) == const char));
@ -267,7 +245,7 @@ template CopyTypeQualifiers(From, To)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(CopyTypeQualifiers!(int, char) == char)); static assert(is(CopyTypeQualifiers!(int, char) == char));
static assert(is(CopyTypeQualifiers!(const int, char) == const char)); static assert(is(CopyTypeQualifiers!(const int, char) == const char));
@ -319,7 +297,7 @@ if (isIntegral!T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Unsigned!byte == ubyte)); static assert(is(Unsigned!byte == ubyte));
static assert(is(Unsigned!short == ushort)); static assert(is(Unsigned!short == ushort));
@ -372,7 +350,7 @@ if (isIntegral!T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Signed!ubyte == byte)); static assert(is(Signed!ubyte == byte));
static assert(is(Signed!ushort == short)); static assert(is(Signed!ushort == short));
@ -408,7 +386,7 @@ template PointerTarget(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(PointerTarget!(bool*) == bool)); static assert(is(PointerTarget!(bool*) == bool));
static assert(is(PointerTarget!(const bool*) == const bool)); static assert(is(PointerTarget!(const bool*) == const bool));
@ -435,7 +413,7 @@ template KeyType(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(KeyType!(int[string]) == string)); static assert(is(KeyType!(int[string]) == string));
static assert(!is(KeyType!(int[15]))); static assert(!is(KeyType!(int[15])));
@ -460,7 +438,7 @@ template ValueType(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(ValueType!(int[string]) == int)); static assert(is(ValueType!(int[string]) == int));
static assert(!is(ValueType!(int[15]))); static assert(!is(ValueType!(int[15])));
@ -482,7 +460,7 @@ if (isScalarType!T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(Promoted!bool == int)); static assert(is(Promoted!bool == int));
static assert(is(Promoted!byte == int)); static assert(is(Promoted!byte == int));
@ -508,7 +486,7 @@ pure nothrow @safe @nogc unittest
alias InoutOf(T) = inout(T); alias InoutOf(T) = inout(T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(InoutOf!int == inout int)); static assert(is(InoutOf!int == inout int));
} }
@ -524,7 +502,7 @@ pure nothrow @safe @nogc unittest
alias ConstOf(T) = const(T); alias ConstOf(T) = const(T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(ConstOf!int == const int)); static assert(is(ConstOf!int == const int));
} }
@ -540,7 +518,7 @@ pure nothrow @safe @nogc unittest
alias SharedOf(T) = shared(T); alias SharedOf(T) = shared(T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(SharedOf!int == shared int)); static assert(is(SharedOf!int == shared int));
} }
@ -556,7 +534,7 @@ pure nothrow @safe @nogc unittest
alias SharedInoutOf(T) = shared(inout T); alias SharedInoutOf(T) = shared(inout T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(SharedInoutOf!int == shared inout int)); static assert(is(SharedInoutOf!int == shared inout int));
} }
@ -572,7 +550,7 @@ pure nothrow @safe @nogc unittest
alias SharedConstOf(T) = shared(const T); alias SharedConstOf(T) = shared(const T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(SharedConstOf!int == shared const int)); static assert(is(SharedConstOf!int == shared const int));
} }
@ -588,7 +566,7 @@ pure nothrow @safe @nogc unittest
alias ImmutableOf(T) = immutable(T); alias ImmutableOf(T) = immutable(T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(ImmutableOf!int == immutable int)); static assert(is(ImmutableOf!int == immutable int));
} }
@ -604,7 +582,7 @@ pure nothrow @safe @nogc unittest
alias InoutConstOf(T) = inout(const T); alias InoutConstOf(T) = inout(const T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(InoutConstOf!int == inout const int)); static assert(is(InoutConstOf!int == inout const int));
} }
@ -620,7 +598,7 @@ pure nothrow @safe @nogc unittest
alias SharedInoutConstOf(T) = shared(inout const T); alias SharedInoutConstOf(T) = shared(inout const T);
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
static assert(is(SharedInoutConstOf!int == shared inout const int)); static assert(is(SharedInoutConstOf!int == shared inout const int));
} }
@ -675,7 +653,7 @@ template QualifierOf(T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
alias MutableOf = QualifierOf!int; alias MutableOf = QualifierOf!int;
static assert(is(MutableOf!uint == uint)); static assert(is(MutableOf!uint == uint));
@ -721,7 +699,7 @@ pure nothrow @safe @nogc unittest
*/ */
alias TypeOf(T) = T; alias TypeOf(T) = T;
/// Ditto. /// ditto
template TypeOf(alias T) template TypeOf(alias T)
if (isExpressions!T || isTemplate!T) if (isExpressions!T || isTemplate!T)
{ {
@ -729,7 +707,7 @@ if (isExpressions!T || isTemplate!T)
} }
/// ///
pure nothrow @safe @nogc unittest @nogc nothrow pure @safe unittest
{ {
struct S(T) struct S(T)
{ {

View File

@ -15,9 +15,9 @@
module tanya.net.inet; module tanya.net.inet;
import std.math; import std.math;
import std.range.primitives;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.primitive;
/** /**
* Represents an unsigned integer as an $(D_KEYWORD ubyte) range. * Represents an unsigned integer as an $(D_KEYWORD ubyte) range.

View File

@ -14,10 +14,14 @@
*/ */
module tanya.net.uri; module tanya.net.uri;
import std.ascii : isAlphaNum, isDigit; import tanya.encoding.ascii;
import std.uni : isAlpha, isNumber;
import tanya.memory; import tanya.memory;
version (unittest)
{
import tanya.test.assertion;
}
/** /**
* Thrown if an invalid URI was specified. * Thrown if an invalid URI was specified.
*/ */
@ -199,8 +203,8 @@ struct URL
this.pass = source[start + i + 1 .. pos]; this.pass = source[start + i + 1 .. pos];
} }
} }
else if (!c.isAlpha && else if (!c.isAlpha() &&
!c.isNumber && !c.isDigit() &&
c != '!' && c != '!' &&
c != ';' && c != ';' &&
c != '=' && c != '=' &&
@ -325,7 +329,7 @@ struct URL
} }
/// ///
@nogc unittest @nogc pure @system unittest
{ {
auto u = URL("example.org"); auto u = URL("example.org");
assert(u.path == "example.org"); assert(u.path == "example.org");
@ -378,7 +382,7 @@ struct URL
assert(u.fragment == "fragment"); assert(u.fragment == "fragment");
} }
private @nogc unittest @nogc pure @system unittest
{ {
auto u = URL("127.0.0.1"); auto u = URL("127.0.0.1");
assert(u.path == "127.0.0.1"); assert(u.path == "127.0.0.1");
@ -447,83 +451,17 @@ private @nogc unittest
assert(u.path == "h_tp:asdf"); assert(u.path == "h_tp:asdf");
} }
private @nogc unittest @nogc pure @system unittest
{ {
URIException exception; assertThrown!URIException(() => URL("http://:80"));
try assertThrown!URIException(() => URL(":80"));
{ assertThrown!URIException(() => URL("http://u1:p1@u2:p2@example.org"));
auto u = URL("http://:80"); assertThrown!URIException(() => URL("http://blah.com:port"));
} assertThrown!URIException(() => URL("http://blah.com:66000"));
catch (URIException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
URIException exception;
try
{
auto u = URL(":80");
}
catch (URIException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
URIException exception;
try
{
auto u = URL("http://user1:pass1@user2:pass2@example.org");
}
catch (URIException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
URIException exception;
try
{
auto u = URL("http://blah.com:port");
}
catch (URIException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
}
private @nogc unittest
{
URIException exception;
try
{
auto u = URL("http://blah.com:66000");
}
catch (URIException e)
{
exception = e;
}
assert(exception !is null);
defaultAllocator.dispose(exception);
} }
// Issue 254: https://issues.caraus.io/issues/254. // Issue 254: https://issues.caraus.io/issues/254.
private @system @nogc unittest @nogc pure @system unittest
{ {
auto u = URL("ftp://"); auto u = URL("ftp://");
assert(u.scheme == "ftp"); assert(u.scheme == "ftp");
@ -554,14 +492,14 @@ if (T == "scheme"
return mixin("ret." ~ T); return mixin("ret." ~ T);
} }
/// Ditto. /// ditto
URL parseURL(const char[] source) @nogc URL parseURL(const char[] source) @nogc pure
{ {
return URL(source); return URL(source);
} }
/// ///
@nogc unittest @nogc pure @system unittest
{ {
auto u = parseURL("http://example.org:5326"); auto u = parseURL("http://example.org:5326");
assert(u.scheme == parseURL!"scheme"("http://example.org:5326")); assert(u.scheme == parseURL!"scheme"("http://example.org:5326"));

View File

@ -17,7 +17,7 @@ module tanya.network.socket;
import core.stdc.errno; import core.stdc.errno;
import core.time; import core.time;
import std.algorithm.comparison; import std.algorithm.comparison;
public import std.socket : SocketOptionLevel, SocketOption; public import std.socket : SocketOption, SocketOptionLevel;
import std.traits; import std.traits;
import std.typecons; import std.typecons;
import tanya.memory; import tanya.memory;
@ -44,12 +44,52 @@ version (Posix)
} }
else version (Windows) else version (Windows)
{ {
import core.sys.windows.winbase : ERROR_IO_INCOMPLETE,
ERROR_IO_PENDING,
GetModuleHandle,
GetProcAddress;
import core.sys.windows.winsock2 : accept,
addrinfo,
bind,
closesocket,
FIONBIO,
freeaddrinfo,
getaddrinfo,
getsockopt,
ioctlsocket,
listen,
MSG_DONTROUTE,
MSG_OOB,
MSG_PEEK,
recv,
SD_BOTH,
SD_RECEIVE,
SD_SEND,
send,
setsockopt,
shutdown,
SOCKADDR,
sockaddr,
sockaddr_in,
sockaddr_in6,
SOCKADDR_STORAGE,
socket,
socklen_t,
SOL_SOCKET,
SO_TYPE,
WSAGetLastError;
import tanya.async.iocp; import tanya.async.iocp;
import core.sys.windows.basetyps; import tanya.sys.windows.def;
import core.sys.windows.mswsock; import tanya.sys.windows.error : ECONNABORTED = WSAECONNABORTED,
import core.sys.windows.winbase; ENOBUFS = WSAENOBUFS,
import core.sys.windows.windef; EOPNOTSUPP = WSAEOPNOTSUPP,
import core.sys.windows.winsock2; EPROTONOSUPPORT = WSAEPROTONOSUPPORT,
EPROTOTYPE = WSAEPROTOTYPE,
ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT,
ETIMEDOUT = WSAETIMEDOUT,
EWOULDBLOCK = WSAEWOULDBLOCK;
public import tanya.sys.windows.winbase;
public import tanya.sys.windows.winsock2;
enum SocketType : size_t enum SocketType : size_t
{ {
@ -58,177 +98,6 @@ else version (Windows)
private alias LingerField = ushort; private alias LingerField = ushort;
enum : uint
{
IOC_UNIX = 0x00000000,
IOC_WS2 = 0x08000000,
IOC_PROTOCOL = 0x10000000,
IOC_VOID = 0x20000000, // No parameters.
IOC_OUT = 0x40000000, // Copy parameters back.
IOC_IN = 0x80000000, // Copy parameters into.
IOC_VENDOR = 0x18000000,
IOC_INOUT = (IOC_IN | IOC_OUT), // Copy parameter into and get back.
}
template _WSAIO(int x, int y)
{
enum _WSAIO = IOC_VOID | x | y;
}
template _WSAIOR(int x, int y)
{
enum _WSAIOR = IOC_OUT | x | y;
}
template _WSAIOW(int x, int y)
{
enum _WSAIOW = IOC_IN | x | y;
}
template _WSAIORW(int x, int y)
{
enum _WSAIORW = IOC_INOUT | x | y;
}
alias SIO_ASSOCIATE_HANDLE = _WSAIOW!(IOC_WS2, 1);
alias SIO_ENABLE_CIRCULAR_QUEUEING = _WSAIO!(IOC_WS2, 2);
alias SIO_FIND_ROUTE = _WSAIOR!(IOC_WS2, 3);
alias SIO_FLUSH = _WSAIO!(IOC_WS2, 4);
alias SIO_GET_BROADCAST_ADDRESS = _WSAIOR!(IOC_WS2, 5);
alias SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW!(IOC_WS2, 6);
alias SIO_GET_QOS = _WSAIORW!(IOC_WS2, 7);
alias SIO_GET_GROUP_QOS = _WSAIORW!(IOC_WS2, 8);
alias SIO_MULTIPOINT_LOOPBACK = _WSAIOW!(IOC_WS2, 9);
alias SIO_MULTICAST_SCOPE = _WSAIOW!(IOC_WS2, 10);
alias SIO_SET_QOS = _WSAIOW!(IOC_WS2, 11);
alias SIO_SET_GROUP_QOS = _WSAIOW!(IOC_WS2, 12);
alias SIO_TRANSLATE_HANDLE = _WSAIORW!(IOC_WS2, 13);
alias SIO_ROUTING_INTERFACE_QUERY = _WSAIORW!(IOC_WS2, 20);
alias SIO_ROUTING_INTERFACE_CHANGE = _WSAIOW!(IOC_WS2, 21);
alias SIO_ADDRESS_LIST_QUERY = _WSAIOR!(IOC_WS2, 22);
alias SIO_ADDRESS_LIST_CHANGE = _WSAIO!(IOC_WS2, 23);
alias SIO_QUERY_TARGET_PNP_HANDLE = _WSAIOR!(IOC_WS2, 24);
alias SIO_NSP_NOTIFY_CHANGE = _WSAIOW!(IOC_WS2, 25);
private alias GROUP = uint;
enum
{
WSA_FLAG_OVERLAPPED = 0x01,
MAX_PROTOCOL_CHAIN = 7,
WSAPROTOCOL_LEN = 255,
}
struct WSAPROTOCOLCHAIN
{
int ChainLen;
DWORD[MAX_PROTOCOL_CHAIN] ChainEntries;
}
alias LPWSAPROTOCOLCHAIN = WSAPROTOCOLCHAIN*;
struct WSAPROTOCOL_INFO
{
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
TCHAR[WSAPROTOCOL_LEN + 1] szProtocol;
}
alias LPWSAPROTOCOL_INFO = WSAPROTOCOL_INFO*;
extern (Windows) @nogc nothrow
{
private SOCKET WSASocketW(int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags);
int WSARecv(SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
LPOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
int WSASend(SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
DWORD lpFlags,
LPOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
int WSAIoctl(SOCKET s,
uint dwIoControlCode,
void* lpvInBuffer,
uint cbInBuffer,
void* lpvOutBuffer,
uint cbOutBuffer,
uint* lpcbBytesReturned,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
alias LPFN_ACCEPTEX = BOOL function(SOCKET,
SOCKET,
PVOID,
DWORD,
DWORD,
DWORD,
LPDWORD,
LPOVERLAPPED);
}
alias WSASocket = WSASocketW;
alias LPFN_GETACCEPTEXSOCKADDRS = VOID function(PVOID,
DWORD,
DWORD,
DWORD,
SOCKADDR**,
LPINT,
SOCKADDR**,
LPINT);
const GUID WSAID_GETACCEPTEXSOCKADDRS = {
0xb5367df2, 0xcbac, 0x11cf,
[ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 ],
};
struct WSABUF
{
ULONG len;
CHAR* buf;
}
alias WSABUF* LPWSABUF;
struct WSAOVERLAPPED
{
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union
{
struct
{
DWORD Offset;
DWORD OffsetHigh;
}
PVOID Pointer;
}
HANDLE hEvent;
}
alias LPWSAOVERLAPPED = WSAOVERLAPPED*;
enum SO_UPDATE_ACCEPT_CONTEXT = 0x700B;
enum OverlappedSocketEvent enum OverlappedSocketEvent
{ {
accept = 1, accept = 1,
@ -241,13 +110,38 @@ else version (Windows)
private WSABUF buffer; private WSABUF buffer;
} }
/**
* Socket returned if a connection has been established.
*
* Note: Available only on Windows.
*/
class OverlappedConnectedSocket : ConnectedSocket class OverlappedConnectedSocket : ConnectedSocket
{ {
/**
* Create a socket.
*
* Params:
* handle = Socket handle.
* af = Address family.
*/
this(SocketType handle, AddressFamily af) @nogc this(SocketType handle, AddressFamily af) @nogc
{ {
super(handle, af); super(handle, af);
} }
/**
* Begins to asynchronously receive data from a connected socket.
*
* Params:
* buffer = Storage location for the received data.
* flags = Flags.
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*/
bool beginReceive(ubyte[] buffer, bool beginReceive(ubyte[] buffer,
SocketState overlapped, SocketState overlapped,
Flags flags = Flags(Flag.none)) @nogc @trusted Flags flags = Flags(Flag.none)) @nogc @trusted
@ -260,12 +154,12 @@ else version (Windows)
overlapped.buffer.buf = cast(char*) buffer.ptr; overlapped.buffer.buf = cast(char*) buffer.ptr;
auto result = WSARecv(handle_, auto result = WSARecv(handle_,
&overlapped.buffer, cast(WSABUF*) &overlapped.buffer,
1u, 1u,
NULL, null,
&receiveFlags, &receiveFlags,
&overlapped.overlapped, &overlapped.overlapped,
NULL); null);
if (result == socketError && !wouldHaveBlocked) if (result == socketError && !wouldHaveBlocked)
{ {
@ -274,6 +168,18 @@ else version (Windows)
return result == 0; return result == 0;
} }
/**
* Ends a pending asynchronous read.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Number of bytes received.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*
* Postcondition: $(D_INLINECODE result >= 0).
*/
int endReceive(SocketState overlapped) @nogc @trusted int endReceive(SocketState overlapped) @nogc @trusted
out (count) out (count)
{ {
@ -298,6 +204,19 @@ else version (Windows)
return lpNumber; return lpNumber;
} }
/**
* Sends data asynchronously to a connected socket.
*
* Params:
* buffer = Data to be sent.
* flags = Flags.
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) if unable to send.
*/
bool beginSend(ubyte[] buffer, bool beginSend(ubyte[] buffer,
SocketState overlapped, SocketState overlapped,
Flags flags = Flags(Flag.none)) @nogc @trusted Flags flags = Flags(Flag.none)) @nogc @trusted
@ -310,10 +229,10 @@ else version (Windows)
auto result = WSASend(handle_, auto result = WSASend(handle_,
&overlapped.buffer, &overlapped.buffer,
1u, 1u,
NULL, null,
cast(DWORD) flags, cast(DWORD) flags,
&overlapped.overlapped, &overlapped.overlapped,
NULL); null);
if (result == socketError && !wouldHaveBlocked) if (result == socketError && !wouldHaveBlocked)
{ {
@ -323,6 +242,18 @@ else version (Windows)
return result == 0; return result == 0;
} }
/**
* Ends a pending asynchronous send.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Number of bytes sent.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*
* Postcondition: $(D_INLINECODE result >= 0).
*/
int endSend(SocketState overlapped) @nogc @trusted int endSend(SocketState overlapped) @nogc @trusted
out (count) out (count)
{ {
@ -344,11 +275,22 @@ else version (Windows)
} }
} }
/**
* Windows stream socket overlapped I/O.
*/
class OverlappedStreamSocket : StreamSocket class OverlappedStreamSocket : StreamSocket
{ {
// Accept extension function pointer. // Accept extension function pointer.
package LPFN_ACCEPTEX acceptExtension; package LPFN_ACCEPTEX acceptExtension;
/**
* Create a socket.
*
* Params:
* af = Address family.
*
* Throws: $(D_PSYMBOL SocketException) on errors.
*/
this(AddressFamily af) @nogc @trusted this(AddressFamily af) @nogc @trusted
{ {
super(af); super(af);
@ -368,8 +310,8 @@ else version (Windows)
&acceptExtension, &acceptExtension,
acceptExtension.sizeof, acceptExtension.sizeof,
&dwBytes, &dwBytes,
NULL, null,
NULL); null);
if (!result == socketError) if (!result == socketError)
{ {
throw make!SocketException(defaultAllocator, throw make!SocketException(defaultAllocator,
@ -377,6 +319,17 @@ else version (Windows)
} }
} }
/**
* Begins an asynchronous operation to accept an incoming connection attempt.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) on accept errors.
*/
bool beginAccept(SocketState overlapped) @nogc @trusted bool beginAccept(SocketState overlapped) @nogc @trusted
{ {
auto socket = cast(SocketType) socket(addressFamily, 1, 0); auto socket = cast(SocketType) socket(addressFamily, 1, 0);
@ -412,6 +365,17 @@ else version (Windows)
return result == TRUE; return result == TRUE;
} }
/**
* Asynchronously accepts an incoming connection attempt and creates a
* new socket to handle remote host communication.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Connected socket.
*
* Throws: $(D_PSYMBOL SocketException) if unable to accept.
*/
OverlappedConnectedSocket endAccept(SocketState overlapped) OverlappedConnectedSocket endAccept(SocketState overlapped)
@nogc @trusted @nogc @trusted
{ {
@ -433,133 +397,6 @@ else version (Windows)
} }
} }
} }
else version (D_Ddoc)
{
/// Native socket representation type.
enum SocketType;
/**
* Socket returned if a connection has been established.
*
* Note: Available only on Windows.
*/
class OverlappedConnectedSocket : ConnectedSocket
{
/**
* Create a socket.
*
* Params:
* handle = Socket handle.
* af = Address family.
*/
this(SocketType handle, AddressFamily af) @nogc;
/**
* Begins to asynchronously receive data from a connected socket.
*
* Params:
* buffer = Storage location for the received data.
* flags = Flags.
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*/
bool beginReceive(ubyte[] buffer,
SocketState overlapped,
Flags flags = Flags(Flag.none)) @nogc @trusted;
/**
* Ends a pending asynchronous read.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Number of bytes received.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*
* Postcondition: $(D_INLINECODE result >= 0).
*/
int endReceive(SocketState overlapped) @nogc @trusted;
/**
* Sends data asynchronously to a connected socket.
*
* Params:
* buffer = Data to be sent.
* flags = Flags.
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) if unable to send.
*/
bool beginSend(ubyte[] buffer,
SocketState overlapped,
Flags flags = Flags(Flag.none)) @nogc @trusted;
/**
* Ends a pending asynchronous send.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Number of bytes sent.
*
* Throws: $(D_PSYMBOL SocketException) if unable to receive.
*
* Postcondition: $(D_INLINECODE result >= 0).
*/
int endSend(SocketState overlapped) @nogc @trusted;
}
/**
* Windows stream socket overlapped I/O.
*/
class OverlappedStreamSocket : StreamSocket
{
/**
* Create a socket.
*
* Params:
* af = Address family.
*
* Throws: $(D_PSYMBOL SocketException) on errors.
*/
this(AddressFamily af) @nogc @trusted;
/**
* Begins an asynchronous operation to accept an incoming connection attempt.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
* $(D_KEYWORD false) otherwise.
*
* Throws: $(D_PSYMBOL SocketException) on accept errors.
*/
bool beginAccept(SocketState overlapped) @nogc @trusted;
/**
* Asynchronously accepts an incoming connection attempt and creates a
* new socket to handle remote host communication.
*
* Params:
* overlapped = Unique operation identifier.
*
* Returns: Connected socket.
*
* Throws: $(D_PSYMBOL SocketException) if unable to accept.
*/
OverlappedConnectedSocket endAccept(SocketState overlapped)
@nogc @trusted;
}
}
/** /**
* Socket option that specifies what should happen when the socket that * Socket option that specifies what should happen when the socket that

View File

@ -234,7 +234,7 @@ struct ErrorCode
return this.value_; return this.value_;
} }
/// Ditto. /// ditto
ErrorNo opCast(T : int)() const ErrorNo opCast(T : int)() const
{ {
return this.value_; return this.value_;
@ -264,7 +264,7 @@ struct ErrorCode
return this; return this;
} }
/// Ditto. /// ditto
ref ErrorCode opAssign()(auto ref const ErrorCode that) ref ErrorCode opAssign()(auto ref const ErrorCode that)
pure nothrow @safe @nogc pure nothrow @safe @nogc
{ {
@ -305,7 +305,7 @@ struct ErrorCode
return this.value_ == that; return this.value_ == that;
} }
/// Ditto. /// ditto
bool opEquals()(auto ref const ErrorCode that) bool opEquals()(auto ref const ErrorCode that)
const pure nothrow @safe @nogc const pure nothrow @safe @nogc
{ {

View File

@ -143,7 +143,7 @@ body
array = array[1 .. $]; array = array[1 .. $];
} }
/// Ditto. /// ditto
void popBack(T)(ref T[] array) void popBack(T)(ref T[] array)
in in
{ {

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** /**
* This package contains generic function and templates to be used with D * This package contains generic functions and templates to be used with D
* ranges. * ranges.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017.
@ -16,3 +16,4 @@
module tanya.range; module tanya.range;
public import tanya.range.array; public import tanya.range.array;
public import tanya.range.primitive;

View File

@ -0,0 +1,897 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This module defines primitives for working with ranges.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/range/primitive.d,
* tanya/range/primitive.d)
*/
module tanya.range.primitive;
import tanya.meta.trait;
import tanya.meta.transform;
/**
* Returns the element type of the range $(D_PARAM R).
*
* Element type is the return type of such primitives like
* $(D_INLINECODE R.front) and (D_INLINECODE R.back) or the array base type.
*
* If $(D_PARAM R) is a string, $(D_PSYMBOL ElementType) doesn't distinguish
* between narrow and wide strings, it just returns the base type of the
* underlying array ($(D_KEYWORD char), $(D_KEYWORD wchar) or
* $(D_KEYWORD dchar)).
*
* Params:
* R = Any range type.
*
* Returns: Element type of the range $(D_PARAM R).
*/
template ElementType(R)
if (isInputRange!R)
{
static if (is(R U : U[]))
{
alias ElementType = U;
}
else
{
alias ElementType = ReturnType!((R r) => r.front());
}
}
/**
* Detects whether $(D_PARAM R) has a length property.
*
* $(D_PARAM R) does not have to be a range to support the length.
*
* Length mustn't be a $(D_KEYWORD @property) or a function, it can be a member
* variable or $(D_KEYWORD enum). But its type (or the type returned by the
* appropriate function) should be $(D_KEYWORD size_t), otherwise
* $(D_PSYMBOL hasLength) is $(D_KEYWORD false).
*
* All dynamic arrays except $(D_KEYWORD void)-arrays have length.
*
* Params:
* R = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) has a length property,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isInfinite).
*/
template hasLength(R)
{
enum bool hasLength = is(ReturnType!((R r) => r.length) == size_t)
&& !is(ElementType!R == void);
}
///
pure nothrow @safe @nogc unittest
{
static assert(hasLength!(char[]));
static assert(hasLength!(int[]));
static assert(hasLength!(const(int)[]));
struct A
{
enum size_t length = 1;
}
static assert(hasLength!(A));
struct B
{
@property size_t length() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(hasLength!(B));
struct C
{
@property const(size_t) length() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(!hasLength!(C));
}
/**
* Determines whether $(D_PARAM R) is a forward range with slicing support
* ($(D_INLINECODE R[i .. j])).
*
* For finite ranges, the result of `opSlice()` must be of the same type as the
* original range. If the range defines opDollar, it must support subtraction.
*
* For infinite ranges, the result of `opSlice()` must be of the same type as
* the original range only if it defines `opDollar()`. Otherwise it can be any
* forward range.
*
* For both finite and infinite ranges, the result of `opSlice()` must have
* length.
*
* Params:
* R = The type to be tested.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) supports slicing,
* $(D_KEYWORD false) otherwise.
*/
template hasSlicing(R)
{
private enum bool hasDollar = is(typeof((R r) => r[0 .. $]));
private enum bool subDollar = !hasDollar
|| isInfinite!R
|| is(ReturnType!((R r) => r[0 .. $ - 1]) == R);
static if (isForwardRange!R
&& is(ReturnType!((R r) => r[0 .. 0]) T)
&& (!hasDollar || is(ReturnType!((R r) => r[0 .. $]) == R))
&& subDollar
&& isForwardRange!(ReturnType!((ref R r) => r[0 .. 0])))
{
enum bool hasSlicing = (is(T == R) || isInfinite!R)
&& hasLength!T;
}
else
{
enum bool hasSlicing = false;
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(hasSlicing!(int[]));
static assert(hasSlicing!(const(int)[]));
static assert(hasSlicing!(dstring));
static assert(hasSlicing!(string));
static assert(!hasSlicing!(const int[]));
static assert(!hasSlicing!(void[]));
struct A
{
int front() pure nothrow @safe @nogc
{
return 0;
}
void popFront() pure nothrow @safe @nogc
{
}
bool empty() const pure nothrow @safe @nogc
{
return false;
}
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
@property size_t length() const pure nothrow @safe @nogc
{
return 0;
}
typeof(this) opSlice(const size_t i, const size_t j)
pure nothrow @safe @nogc
{
return this;
}
}
static assert(hasSlicing!A);
struct B
{
struct Dollar
{
}
int front() pure nothrow @safe @nogc
{
return 0;
}
void popFront() pure nothrow @safe @nogc
{
}
bool empty() const pure nothrow @safe @nogc
{
return false;
}
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
@property size_t length() const pure nothrow @safe @nogc
{
return 0;
}
@property Dollar opDollar() const pure nothrow @safe @nogc
{
return Dollar();
}
typeof(this) opSlice(const size_t i, const Dollar j)
pure nothrow @safe @nogc
{
return this;
}
}
static assert(!hasSlicing!B);
struct C
{
int front() pure nothrow @safe @nogc
{
return 0;
}
void popFront() pure nothrow @safe @nogc
{
}
enum bool empty = false;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
typeof(this) opSlice(const size_t i, const size_t j)
pure nothrow @safe @nogc
{
return this;
}
}
static assert(!hasSlicing!C);
struct D
{
struct Range
{
int front() pure nothrow @safe @nogc
{
return 0;
}
void popFront() pure nothrow @safe @nogc
{
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
@property size_t length() const pure nothrow @safe @nogc
{
return 0;
}
}
int front() pure nothrow @safe @nogc
{
return 0;
}
void popFront() pure nothrow @safe @nogc
{
}
enum bool empty = false;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
Range opSlice(const size_t i, const size_t j)
pure nothrow @safe @nogc
{
return Range();
}
}
static assert(hasSlicing!D);
}
version (unittest)
{
mixin template InputRangeStub()
{
@property int front() pure nothrow @safe @nogc
{
return 0;
}
@property bool empty() const pure nothrow @safe @nogc
{
return false;
}
void popFront() pure nothrow @safe @nogc
{
}
}
mixin template BidirectionalRangeStub()
{
@property int back() pure nothrow @safe @nogc
{
return 0;
}
void popBack() pure nothrow @safe @nogc
{
}
}
}
private template isDynamicArrayRange(R)
{
static if (is(R E : E[]))
{
enum bool isDynamicArrayRange = !is(E == void);
}
else
{
enum bool isDynamicArrayRange = false;
}
}
/**
* Determines whether $(D_PARAM R) is an input range.
*
* An input range should define following primitives:
*
* $(UL
* $(LI front)
* $(LI empty)
* $(LI popFront)
* )
*
* Params:
* R = The type to be tested.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is an input range,
* $(D_KEYWORD false) otherwise.
*/
template isInputRange(R)
{
static if (is(ReturnType!((R r) => r.front()) U)
&& is(ReturnType!((R r) => r.empty) == bool))
{
enum bool isInputRange = !is(U == void)
&& is(typeof(R.popFront()));
}
else
{
enum bool isInputRange = isDynamicArrayRange!R;
}
}
///
pure nothrow @safe @nogc unittest
{
static struct Range
{
void popFront() pure nothrow @safe @nogc
{
}
int front() pure nothrow @safe @nogc
{
return 0;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
}
static assert(isInputRange!Range);
static assert(isInputRange!(int[]));
static assert(!isInputRange!(void[]));
}
private pure nothrow @safe @nogc unittest
{
static struct Range1(T)
{
void popFront()
{
}
int front()
{
return 0;
}
T empty() const
{
return true;
}
}
static assert(!isInputRange!(Range1!int));
static assert(!isInputRange!(Range1!(const bool)));
static struct Range2
{
int popFront() pure nothrow @safe @nogc
{
return 100;
}
int front() pure nothrow @safe @nogc
{
return 100;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
}
static assert(isInputRange!Range2);
static struct Range3
{
void popFront() pure nothrow @safe @nogc
{
}
void front() pure nothrow @safe @nogc
{
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
}
static assert(!isInputRange!Range3);
static struct Range4
{
void popFront() pure nothrow @safe @nogc
{
}
int front() pure nothrow @safe @nogc
{
return 0;
}
enum bool empty = false;
}
static assert(isInputRange!Range4);
}
/**
* Determines whether $(D_PARAM R) is a forward range.
*
* A forward range is an input range that also defines:
*
* $(UL
* $(LI save)
* )
*
* Params:
* R = The type to be tested.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is a forward range,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isInputRange).
*/
template isForwardRange(R)
{
static if (is(ReturnType!((R r) => r.save()) U))
{
enum bool isForwardRange = isInputRange!R && is(U == R);
}
else
{
enum bool isForwardRange = isDynamicArrayRange!R;
}
}
///
pure nothrow @safe @nogc unittest
{
static struct Range
{
void popFront() pure nothrow @safe @nogc
{
}
int front() pure nothrow @safe @nogc
{
return 0;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
}
static assert(isForwardRange!Range);
static assert(isForwardRange!(int[]));
static assert(!isForwardRange!(void[]));
}
private pure nothrow @safe @nogc unittest
{
static struct Range1
{
}
static struct Range2
{
mixin InputRangeStub;
Range1 save() pure nothrow @safe @nogc
{
return Range1();
}
}
static assert(!isForwardRange!Range2);
static struct Range3
{
mixin InputRangeStub;
const(typeof(this)) save() const pure nothrow @safe @nogc
{
return this;
}
}
static assert(!isForwardRange!Range3);
}
/**
* Determines whether $(D_PARAM R) is a bidirectional range.
*
* A bidirectional range is a forward range that also defines:
*
* $(UL
* $(LI back)
* $(LI popBack)
* )
*
* Params:
* R = The type to be tested.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is a bidirectional range,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isForwardRange).
*/
template isBidirectionalRange(R)
{
static if (is(ReturnType!((R r) => r.back()) U))
{
enum bool isBidirectionalRange = isForwardRange!R
&& is(U == ReturnType!((R r) => r.front()))
&& is(typeof(R.popBack()));
}
else
{
enum bool isBidirectionalRange = isDynamicArrayRange!R;
}
}
///
pure nothrow @safe @nogc unittest
{
static struct Range
{
void popFront() pure nothrow @safe @nogc
{
}
void popBack() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
@property int back() pure nothrow @safe @nogc
{
return 0;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
Range save() pure nothrow @safe @nogc
{
return this;
}
}
static assert(isBidirectionalRange!Range);
static assert(isBidirectionalRange!(int[]));
static assert(!isBidirectionalRange!(void[]));
}
private nothrow @safe @nogc unittest
{
static struct Range(T, U)
{
void popFront() pure nothrow @safe @nogc
{
}
void popBack() pure nothrow @safe @nogc
{
}
@property T front() pure nothrow @safe @nogc
{
return T.init;
}
@property U back() pure nothrow @safe @nogc
{
return U.init;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
Range save() pure nothrow @safe @nogc
{
return this;
}
}
static assert(!isBidirectionalRange!(Range!(int, uint)));
static assert(!isBidirectionalRange!(Range!(int, const int)));
}
/**
* Determines whether $(D_PARAM R) is a random-access range.
*
* A random-access range is a range that allows random access to its
* elements by index using $(D_INLINECODE [])-operator (defined with
* $(D_INLINECODE opIndex())). Further a random access range should be a
* bidirectional range that also has a length or an infinite forward range.
*
* Params:
* R = The type to be tested.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is a random-access range,
* $(D_KEYWORD false) otherwise.
*
* See_Also: $(D_PSYMBOL isBidirectionalRange),
* $(D_PSYMBOL isForwardRange),
* $(D_PSYMBOL isInfinite),
* $(D_PSYMBOL hasLength).
*/
template isRandomAccessRange(R)
{
static if (is(ReturnType!((R r) => r.opIndex(size_t.init)) U))
{
private enum bool isBidirectional = isBidirectionalRange!R
&& hasLength!R;
private enum bool isForward = isInfinite!R && isForwardRange!R;
enum bool isRandomAccessRange = (isBidirectional || isForward)
&& is(U == ReturnType!((R r) => r.front()));
}
else
{
enum bool isRandomAccessRange = isDynamicArrayRange!R;
}
}
///
pure nothrow @safe @nogc unittest
{
static struct A
{
void popFront() pure nothrow @safe @nogc
{
}
void popBack() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
@property int back() pure nothrow @safe @nogc
{
return 0;
}
bool empty() const pure nothrow @safe @nogc
{
return true;
}
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(const size_t pos) pure nothrow @safe @nogc
{
return 0;
}
size_t length() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(isRandomAccessRange!A);
static assert(isRandomAccessRange!(int[]));
static assert(!isRandomAccessRange!(void[]));
static struct B
{
void popFront() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
enum bool empty = false;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(const size_t pos) pure nothrow @safe @nogc
{
return 0;
}
}
static assert(isRandomAccessRange!B);
}
private pure nothrow @safe @nogc unittest
{
static struct Range1
{
mixin InputRangeStub;
mixin BidirectionalRangeStub;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(const size_t pos) pure nothrow @safe @nogc
{
return 0;
}
}
static assert(!isRandomAccessRange!Range1);
static struct Range2(Args...)
{
mixin InputRangeStub;
mixin BidirectionalRangeStub;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(Args) pure nothrow @safe @nogc
{
return 0;
}
size_t length() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(isRandomAccessRange!(Range2!size_t));
static assert(!isRandomAccessRange!(Range2!()));
static assert(!isRandomAccessRange!(Range2!(size_t, size_t)));
static struct Range3
{
mixin InputRangeStub;
mixin BidirectionalRangeStub;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(const size_t pos1, const size_t pos2 = 0)
pure nothrow @safe @nogc
{
return 0;
}
size_t length() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(isRandomAccessRange!Range3);
static struct Range4
{
mixin InputRangeStub;
mixin BidirectionalRangeStub;
typeof(this) save() pure nothrow @safe @nogc
{
return this;
}
int opIndex(const size_t pos1) pure nothrow @safe @nogc
{
return 0;
}
size_t opDollar() const pure nothrow @safe @nogc
{
return 0;
}
}
static assert(!isRandomAccessRange!Range4);
}
/**
* Determines whether $(D_PARAM R) is an infinite range.
*
* An infinite range is an input range whose `empty` member is defined as
* $(D_KEYWORD enum) which is always $(D_KEYWORD false).
*
* Params:
* R = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM R) is an infinite range,
* $(D_KEYWORD false) otherwise.
*/
template isInfinite(R)
{
static if (isInputRange!R && is(typeof({enum bool e = R.empty;})))
{
enum bool isInfinite = R.empty == false;
}
else
{
enum bool isInfinite = false;
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(!isInfinite!int);
static struct NotRange
{
enum bool empty = false;
}
static assert(!isInfinite!NotRange);
static struct InfiniteRange
{
void popFront() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
enum bool empty = false;
}
static assert(isInfinite!InfiniteRange);
static struct InputRange
{
void popFront() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
@property bool empty() const pure nothrow @safe @nogc
{
return false;
}
}
static assert(!isInfinite!InputRange);
}
private pure nothrow @safe @nogc unittest
{
static struct StaticConstRange
{
void popFront() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
static bool empty = false;
}
static assert(!isInfinite!StaticConstRange);
static struct TrueRange
{
void popFront() pure nothrow @safe @nogc
{
}
@property int front() pure nothrow @safe @nogc
{
return 0;
}
static const bool empty = true;
}
static assert(!isInfinite!TrueRange);
}

View File

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Base type definitions and aliases.
*
* This module doesn't provide aliases for all types used by Windows, but only
* for types that can vary on different platforms. For example there is no
* need to define `INT32` alias for D, since $(D_KEYWORD int) is always a
* 32-bit signed integer. But `int` and its Windows alias `INT` is not the
* same on all platforms in C, so its size can be something differen than
* 32 bit, therefore an $(D_PSYMBOL INT) alias is available in this module.
* $(D_PARAM TCHAR) can be a $(D_KEYWORD char) if Unicode isn't supported or
* $(D_KEYWORD wchar) if Unicode is supported, so $(D_PSYMBOL TCHAR) is
* defined here.
* Also aliases for specific types like $(D_PSYMBOL SOCKET) are defined here.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/def.d,
* tanya/sys/windows/def.d)
*/
module tanya.sys.windows.def;
version (Windows):
alias BYTE = ubyte;
alias TBYTE = wchar; // If Unicode, otherwise char.
alias CHAR = char; // Signed or unsigned char.
alias TCHAR = wchar; // If Unicode, otherwise char.
alias SHORT = short;
alias USHORT = ushort;
alias WORD = ushort;
alias INT = int;
alias UINT = uint;
alias LONG = int;
alias ULONG = uint;
alias DWORD = uint;
alias LONGLONG = long; // Or double.
alias ULONGLONG = ulong; // Or double.
alias DWORDLONG = ulong;
alias FLOAT = float;
alias BOOL = int;
alias BOOLEAN = BYTE;
alias HANDLE = void*;
enum HANDLE INVALID_HANDLE_VALUE = cast(HANDLE) -1;
enum TRUE = 1;
enum FALSE = 0;
align(1) struct GUID
{
uint Data1;
ushort Data2;
ushort Data3;
char[8] Data4;
}

View File

@ -0,0 +1,114 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/error.d,
* tanya/sys/windows/error.d)
*/
module tanya.sys.windows.error;
version (Windows):
private enum WSABASEERR = 10000;
enum
{
WSAEINTR = WSABASEERR + 4,
WSAEBADF = WSABASEERR + 9,
WSAEACCES = WSABASEERR + 13,
WSAEFAULT = WSABASEERR + 14,
WSAEINVAL = WSABASEERR + 22,
WSAEMFILE = WSABASEERR + 24,
WSAEWOULDBLOCK = WSABASEERR + 35,
WSAEINPROGRESS = WSABASEERR + 36,
WSAEALREADY = WSABASEERR + 37,
WSAENOTSOCK = WSABASEERR + 38,
WSAEDESTADDRREQ = WSABASEERR + 39,
WSAEMSGSIZE = WSABASEERR + 40,
WSAEPROTOTYPE = WSABASEERR + 41,
WSAENOPROTOOPT = WSABASEERR + 42,
WSAEPROTONOSUPPORT = WSABASEERR + 43,
WSAESOCKTNOSUPPORT = WSABASEERR + 44,
WSAEOPNOTSUPP = WSABASEERR + 45,
WSAEPFNOSUPPORT = WSABASEERR + 46,
WSAEAFNOSUPPORT = WSABASEERR + 47,
WSAEADDRINUSE = WSABASEERR + 48,
WSAEADDRNOTAVAIL = WSABASEERR + 49,
WSAENETDOWN = WSABASEERR + 50,
WSAENETUNREACH = WSABASEERR + 51,
WSAENETRESET = WSABASEERR + 52,
WSAECONNABORTED = WSABASEERR + 53,
WSAECONNRESET = WSABASEERR + 54,
WSAENOBUFS = WSABASEERR + 55,
WSAEISCONN = WSABASEERR + 56,
WSAENOTCONN = WSABASEERR + 57,
WSAESHUTDOWN = WSABASEERR + 58,
WSAETOOMANYREFS = WSABASEERR + 59,
WSAETIMEDOUT = WSABASEERR + 60,
WSAECONNREFUSED = WSABASEERR + 61,
WSAELOOP = WSABASEERR + 62,
WSAENAMETOOLONG = WSABASEERR + 63,
WSAEHOSTDOWN = WSABASEERR + 64,
WSAEHOSTUNREACH = WSABASEERR + 65,
WSAENOTEMPTY = WSABASEERR + 66,
WSAEPROCLIM = WSABASEERR + 67,
WSAEUSERS = WSABASEERR + 68,
WSAEDQUOT = WSABASEERR + 69,
WSAESTALE = WSABASEERR + 70,
WSAEREMOTE = WSABASEERR + 71,
WSASYSNOTREADY = WSABASEERR + 91,
WSAVERNOTSUPPORTED = WSABASEERR + 92,
WSANOTINITIALISED = WSABASEERR + 93,
WSAEDISCON = WSABASEERR + 101,
WSAENOMORE = WSABASEERR + 102,
WSAECANCELLED = WSABASEERR + 103,
WSAEINVALIDPROCTABLE = WSABASEERR + 104,
WSAEINVALIDPROVIDER = WSABASEERR + 105,
WSAEPROVIDERFAILEDINIT = WSABASEERR + 106,
WSASYSCALLFAILURE = WSABASEERR + 107,
WSASERVICE_NOT_FOUND = WSABASEERR + 108,
WSATYPE_NOT_FOUND = WSABASEERR + 109,
WSA_E_NO_MORE = WSABASEERR + 110,
WSA_E_CANCELLED = WSABASEERR + 111,
WSAEREFUSED = WSABASEERR + 112,
WSAHOST_NOT_FOUND = WSABASEERR + 1001,
WSATRY_AGAIN = WSABASEERR + 1002,
WSANO_RECOVERY = WSABASEERR + 1003,
WSANO_DATA = WSABASEERR + 1004,
WSA_QOS_RECEIVERS = WSABASEERR + 1005,
WSA_QOS_SENDERS = WSABASEERR + 1006,
WSA_QOS_NO_SENDERS = WSABASEERR + 1007,
WSA_QOS_NO_RECEIVERS = WSABASEERR + 1008,
WSA_QOS_REQUEST_CONFIRMED = WSABASEERR + 1009,
WSA_QOS_ADMISSION_FAILURE = WSABASEERR + 1010,
WSA_QOS_POLICY_FAILURE = WSABASEERR + 1011,
WSA_QOS_BAD_STYLE = WSABASEERR + 1012,
WSA_QOS_BAD_OBJECT = WSABASEERR + 1013,
WSA_QOS_TRAFFIC_CTRL_ERROR = WSABASEERR + 1014,
WSA_QOS_GENERIC_ERROR = WSABASEERR + 1015,
WSA_QOS_ESERVICETYPE = WSABASEERR + 1016,
WSA_QOS_EFLOWSPEC = WSABASEERR + 1017,
WSA_QOS_EPROVSPECBUF = WSABASEERR + 1018,
WSA_QOS_EFILTERSTYLE = WSABASEERR + 1019,
WSA_QOS_EFILTERTYPE = WSABASEERR + 1020,
WSA_QOS_EFILTERCOUNT = WSABASEERR + 1021,
WSA_QOS_EOBJLENGTH = WSABASEERR + 1022,
WSA_QOS_EFLOWCOUNT = WSABASEERR + 1023,
WSA_QOS_EUNKOWNPSOBJ = WSABASEERR + 1024,
WSA_QOS_EPOLICYOBJ = WSABASEERR + 1025,
WSA_QOS_EFLOWDESC = WSABASEERR + 1026,
WSA_QOS_EPSFLOWSPEC = WSABASEERR + 1027,
WSA_QOS_EPSFILTERSPEC = WSABASEERR + 1028,
WSA_QOS_ESDMODEOBJ = WSABASEERR + 1029,
WSA_QOS_ESHAPERATEOBJ = WSABASEERR + 1030,
WSA_QOS_RESERVED_PETYPE = WSABASEERR + 1031,
}

View File

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/package.d,
* tanya/sys/windows/package.d)
*/
module tanya.sys.windows;
version (Windows):
public import tanya.sys.windows.def;
public import tanya.sys.windows.error;
public import tanya.sys.windows.winbase;
public import tanya.sys.windows.winsock2;

View File

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Definitions from winbase.h.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/winbase.d,
* tanya/sys/windows/winbase.d)
*/
module tanya.sys.windows.winbase;
version (Windows):
public import tanya.sys.windows.def;
struct OVERLAPPED
{
size_t Internal;
size_t InternalHigh;
union
{
struct
{
DWORD Offset;
DWORD OffsetHigh;
}
void* Pointer;
}
HANDLE hEvent;
}
extern(Windows)
HANDLE CreateIoCompletionPort(HANDLE FileHandle,
HANDLE ExistingCompletionPort,
size_t CompletionKey,
DWORD NumberOfConcurrentThreads)
nothrow @system @nogc;
extern(Windows)
BOOL GetQueuedCompletionStatus(HANDLE CompletionPort,
DWORD* lpNumberOfBytes,
size_t* lpCompletionKey,
OVERLAPPED** lpOverlapped,
DWORD dwMilliseconds) nothrow @system @nogc;
extern(Windows)
BOOL GetOverlappedResult(HANDLE hFile,
OVERLAPPED* lpOverlapped,
DWORD* lpNumberOfBytesTransferred,
BOOL bWait) nothrow @system @nogc;

View File

@ -0,0 +1,219 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Definitions from winsock2.h, ws2def.h and MSWSock.h.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/winsock2.d,
* tanya/sys/windows/winsock2.d)
*/
module tanya.sys.windows.winsock2;
version (Windows):
public import tanya.sys.windows.def;
public import tanya.sys.windows.winbase;
alias SOCKET = size_t;
enum SOCKET INVALID_SOCKET = ~0;
enum SOCKET_ERROR = -1;
enum
{
IOC_UNIX = 0x00000000,
IOC_WS2 = 0x08000000,
IOC_PROTOCOL = 0x10000000,
IOC_VOID = 0x20000000, // No parameters.
IOC_OUT = 0x40000000, // Copy parameters back.
IOC_IN = 0x80000000, // Copy parameters into.
IOC_VENDOR = 0x18000000,
IOC_WSK = (IOC_WS2 | 0x07000000), // _WIN32_WINNT >= 0x0600.
IOC_INOUT = (IOC_IN | IOC_OUT), // Copy parameter into and get back.
}
template _WSAIO(int x, int y)
{
enum _WSAIO = IOC_VOID | x | y;
}
template _WSAIOR(int x, int y)
{
enum _WSAIOR = IOC_OUT | x | y;
}
template _WSAIOW(int x, int y)
{
enum _WSAIOW = IOC_IN | x | y;
}
template _WSAIORW(int x, int y)
{
enum _WSAIORW = IOC_INOUT | x | y;
}
alias SIO_ASSOCIATE_HANDLE = _WSAIOW!(IOC_WS2, 1);
alias SIO_ENABLE_CIRCULAR_QUEUEING = _WSAIO!(IOC_WS2, 2);
alias SIO_FIND_ROUTE = _WSAIOR!(IOC_WS2, 3);
alias SIO_FLUSH = _WSAIO!(IOC_WS2, 4);
alias SIO_GET_BROADCAST_ADDRESS = _WSAIOR!(IOC_WS2, 5);
alias SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW!(IOC_WS2, 6);
alias SIO_GET_QOS = _WSAIORW!(IOC_WS2, 7);
alias SIO_GET_GROUP_QOS = _WSAIORW!(IOC_WS2, 8);
alias SIO_MULTIPOINT_LOOPBACK = _WSAIOW!(IOC_WS2, 9);
alias SIO_MULTICAST_SCOPE = _WSAIOW!(IOC_WS2, 10);
alias SIO_SET_QOS = _WSAIOW!(IOC_WS2, 11);
alias SIO_SET_GROUP_QOS = _WSAIOW!(IOC_WS2, 12);
alias SIO_TRANSLATE_HANDLE = _WSAIORW!(IOC_WS2, 13);
alias SIO_ROUTING_INTERFACE_QUERY = _WSAIORW!(IOC_WS2, 20);
alias SIO_ROUTING_INTERFACE_CHANGE = _WSAIOW!(IOC_WS2, 21);
alias SIO_ADDRESS_LIST_QUERY = _WSAIOR!(IOC_WS2, 22);
alias SIO_ADDRESS_LIST_CHANGE = _WSAIO!(IOC_WS2, 23);
alias SIO_QUERY_TARGET_PNP_HANDLE = _WSAIOR!(IOC_WS2, 24);
alias SIO_NSP_NOTIFY_CHANGE = _WSAIOW!(IOC_WS2, 25);
alias GROUP = uint;
enum
{
WSA_FLAG_OVERLAPPED = 0x01,
WSA_FLAG_MULTIPOINT_C_ROOT = 0x02,
WSA_FLAG_MULTIPOINT_C_LEAF = 0x04,
WSA_FLAG_MULTIPOINT_D_ROOT = 0x08,
WSA_FLAG_MULTIPOINT_D_LEAF = 0x10,
WSA_FLAG_ACCESS_SYSTEM_SECURITY = 0x40,
WSA_FLAG_NO_HANDLE_INHERIT = 0x80,
WSA_FLAG_REGISTERED_IO = 0x100,
}
enum MAX_PROTOCOL_CHAIN = 7;
enum BASE_PROTOCOL = 1;
enum LAYERED_PROTOCOL = 0;
enum WSAPROTOCOL_LEN = 255;
struct WSAPROTOCOLCHAIN
{
int ChainLen;
DWORD[MAX_PROTOCOL_CHAIN] ChainEntries;
}
struct WSABUF
{
ULONG len;
CHAR* buf;
}
struct WSAPROTOCOL_INFO
{
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
TCHAR[WSAPROTOCOL_LEN + 1] szProtocol;
}
const GUID WSAID_GETACCEPTEXSOCKADDRS = {
0xb5367df2, 0xcbac, 0x11cf,
[0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92],
};
const GUID WSAID_ACCEPTEX = {
0xb5367df1, 0xcbac, 0x11cf,
[0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92],
};
alias LPWSAOVERLAPPED_COMPLETION_ROUTINE = void function(DWORD dwError,
DWORD cbTransferred,
OVERLAPPED* lpOverlapped,
DWORD dwFlags) nothrow @nogc;
extern(Windows)
SOCKET WSASocket(int af,
int type,
int protocol,
WSAPROTOCOL_INFO* lpProtocolInfo,
GROUP g,
DWORD dwFlags) nothrow @system @nogc;
extern(Windows)
int WSARecv(SOCKET s,
WSABUF* lpBuffers,
DWORD dwBufferCount,
DWORD* lpNumberOfBytesRecvd,
DWORD* lpFlags,
OVERLAPPED* lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
nothrow @system @nogc;
extern(Windows)
int WSASend(SOCKET s,
WSABUF* lpBuffers,
DWORD dwBufferCount,
DWORD* lpNumberOfBytesRecvd,
DWORD lpFlags,
OVERLAPPED* lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
nothrow @system @nogc;
extern(Windows)
int WSAIoctl(SOCKET s,
uint dwIoControlCode,
void* lpvInBuffer,
uint cbInBuffer,
void* lpvOutBuffer,
uint cbOutBuffer,
uint* lpcbBytesReturned,
OVERLAPPED* lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
nothrow @system @nogc;
alias ADDRESS_FAMILY = USHORT;
struct SOCKADDR
{
ADDRESS_FAMILY sa_family; // Address family.
CHAR[14] sa_data; // Up to 14 bytes of direct address.
}
alias LPFN_GETACCEPTEXSOCKADDRS = void function(void*,
DWORD,
DWORD,
DWORD,
SOCKADDR**,
INT*,
SOCKADDR**,
INT*) nothrow @nogc;
alias LPFN_ACCEPTEX = extern(Windows) BOOL function(SOCKET,
SOCKET,
void*,
DWORD,
DWORD,
DWORD,
DWORD*,
OVERLAPPED*) @nogc nothrow;
enum
{
SO_MAXDG = 0x7009,
SO_MAXPATHDG = 0x700A,
SO_UPDATE_ACCEPT_CONTEXT = 0x700B,
SO_CONNECT_TIME = 0x700C,
SO_UPDATE_CONNECT_CONTEXT = 0x7010,
}

View File

@ -0,0 +1,105 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Additional assertions.
*
* This module provides functions that assert whether a given expression
* satisfies some complex condition, that can't be tested with
* $(D_KEYWORD assert) in a single line. Internally all the functions
* just evaluate the expression and call $(D_KEYWORD assert).
*
* The functions can cause segmentation fault if the module is compiled
* in production mode and the condition fails.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/assertion.d,
* tanya/test/assertion.d)
*/
module tanya.test.assertion;
import tanya.memory;
import tanya.meta.trait;
/**
* Asserts whether the function $(D_PARAM expr) throws an exception of type
* $(D_PARAM E). If it does, the exception is catched and properly destroyed.
* If it doesn't, an assertion error is thrown. If the exception doesn't match
* $(D_PARAM E) type, it isn't catched and escapes.
*
* Params:
* E = Expected exception type.
* T = Throwing function type.
* Args = Argument types of the throwing function.
* expr = Throwing function.
* args = Arguments for $(D_PARAM expr).
*/
void assertThrown(E : Exception, T, Args...)(T expr, auto ref Args args)
if (isSomeFunction!T)
{
try
{
cast(void) expr(args);
assert(false, "Expected exception not thrown");
}
catch (E exception)
{
defaultAllocator.dispose(exception);
}
}
///
@nogc nothrow pure @safe unittest
{
// If you want to test that an expression throws, you can wrap it into an
// arrow function.
static struct CtorThrows
{
this(int i) @nogc pure @safe
{
throw defaultAllocator.make!Exception();
}
}
assertThrown!Exception(() => CtorThrows(8));
}
/**
* Asserts that the function $(D_PARAM expr) doesn't throw.
*
* If it does, the thrown exception is catched, properly destroyed and an
* assertion error is thrown instead.
*
* Params:
* T = Tested function type.
* Args = Argument types of $(D_PARAM expr).
* expr = Tested function.
* args = Arguments for $(D_PARAM expr).
*/
void assertNotThrown(T, Args...)(T expr, auto ref Args args)
if (isSomeFunction!T)
{
try
{
cast(void) expr(args);
}
catch (Exception exception)
{
defaultAllocator.dispose(exception);
assert(false, "Unexpected exception thrown");
}
}
///
@nogc nothrow pure @safe unittest
{
// If you want to test that an expression doesn't throw, you can wrap it
// into an arrow function.
static struct S
{
}
assertNotThrown(() => S());
}

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test suite for $(D_KEYWORD unittest)-blocks.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/package.d,
* tanya/test/package.d)
*/
module tanya.test;
public import tanya.test.assertion;