Skip to content

Commit

Permalink
Setup documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
tkf committed Jun 14, 2021
1 parent b146af8 commit de09bb2
Show file tree
Hide file tree
Showing 20 changed files with 381 additions and 1 deletion.
40 changes: 40 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Documentation

on:
push:
branches:
- master
- actions/trigger/docs
tags: '*'
pull_request:

jobs:
Documenter:
runs-on: ubuntu-latest
env:
GKSwstype: "nul"
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: nightly
# Use `JULIA_PKG_SERVER` mitigation implemented in julia-buildpkg:
- uses: julia-actions/julia-buildpkg@v1
- name: Install Run.jl
run: julia -e 'using Pkg; pkg"add [email protected]"'
- name: Install dependencies
run: julia -e 'using Run; Run.prepare_docs()'
- name: Build and deploy
id: build-and-deploy
if: |
github.event_name == 'push' || (
github.event_name == 'pull_request' &&
!contains(github.head_ref, 'create-pull-request/')
)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCUMENTER_KEY: ${{ secrets.SSH_KEY }}
run: julia -e 'using Run; Run.docs()'
- name: Just build
if: steps.build-and-deploy.outcome == 'skipped'
run: julia -e 'using Run; Run.docs()'
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
julia-version: ['1.6', 'nightly']
julia-version: ['nightly']
fail-fast: false
name: Test Julia ${{ matrix.julia-version }}
steps:
Expand Down
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
site/
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
28 changes: 28 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Documenter
using ConcurrentCollections

makedocs(
sitename = "ConcurrentCollections",
format = Documenter.HTML(),
modules = [ConcurrentCollections],
)

for (root, dirs, files) in walkdir(joinpath(@__DIR__, "build"))
for name in files
path = joinpath(root, name)
if endswith(name, ".html") || name == "search_index.js"
html = replace(
read(path, String),
"ConcurrentCollections.Implementations" => "ConcurrentCollections",
)
write(path, html)
end
end
end

# Documenter can also automatically deploy documentation to gh-pages.
# See "Hosting Documentation" and deploydocs() in the Documenter manual
# for more information.
#=deploydocs(
repo = "<repository url>"
)=#
29 changes: 29 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# ConcurrentCollections.jl

```@index
```

## Collections

```@docs
ConcurrentQueue
ConcurrentStack
WorkStealingDeque
```

## Functions

```@docs
trypop!
trypopfirst!
```

## Experimental

```@docs
ConcurrentDict
modify!
tryget
Keep
Delete
```
2 changes: 2 additions & 0 deletions src/ConcurrentCollections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ end # module Implementations

using .Implementations: ConcurrentQueue, ConcurrentStack, WorkStealingDeque

Implementations.define_docstrings()

end # baremodule ConcurrentCollections
26 changes: 26 additions & 0 deletions src/docs/ConcurrentDict.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ConcurrentDict{K,V}()

Concurrent dictionary. All operations are lock-free except when the dictionary
is resized.

!!! warning
`ConcurrentDict` is experimental because it cannot be implemented with the
builtin atomics.

!!! note
Although tasks `wait` on concurrent modifications (e.g., `setindex!`) during
resize, the worker threads participate in the resize to avoid wasting CPU
resources.

# Examples

```julia
julia> using ConcurrentCollections

julia> dict = ConcurrentDict{String,Int}();

julia> dict["hello"] = 1;

julia> dict["hello"]
1
```
28 changes: 28 additions & 0 deletions src/docs/ConcurrentQueue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ConcurrentQueue{T}()

Concurrent queue of objects of type `T`.

Use `push!` to insert an element at the tail and [`trypopfirst!`](@ref) to
retrieve and remove an element at the head.

Implementation detail: It implements the Michael and Scott queue.

# Examples

```julia
julia> using ConcurrentCollections

julia> queue = ConcurrentQueue{Int}();

julia> push!(queue, 1);

julia> push!(queue, 2);

julia> popfirst!(queue)
1

julia> trypopfirst!(queue)
Some(2)

julia> trypopfirst!(queue) # returns nothing
```
28 changes: 28 additions & 0 deletions src/docs/ConcurrentStack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ConcurrentStack{T}()

Concurrent stack of objects of type `T`.

Use `push!` to insert an element and [`trypop!`](@ref) to retrieve and remove an
element.

It implements the Treiber stack.

# Examples

```julia
julia> using ConcurrentCollections

julia> stack = ConcurrentStack{Int}();

julia> push!(stack, 1);

julia> push!(stack, 2);

julia> pop!(stack)
2

julia> trypop!(stack)
Some(1)

julia> trypop!(stack) # returns nothing
```
24 changes: 24 additions & 0 deletions src/docs/Delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Delete(ans)

A special type used in [`modify!`](@ref) to indicate that a slot should be
removed.

That is to say

```Julia
y = modify!(dict, key) do value
Delete(f(something(value)))
end
y[]
```

is an optimization of

```Julia
r = Ref{Any}()
modify!(dict, key) do value
r[] = f(something(value))
nothing
end
r[]
```
25 changes: 25 additions & 0 deletions src/docs/Keep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Keep(ans)

A special type used in [`modify!`](@ref) to indicate that a slot should be
remain unchanged while propagating the result `ans` of some computation to
the caller.

That is to say,

```Julia
y = modify!(dict, key) do value
Keep(f(something(value)))
end
y[]
```

is an optimization of

```Julia
r = Ref{Any}()
modify!(dict, key) do value
r[] = f(something(value))
Some(value)
end
r[]
```
38 changes: 38 additions & 0 deletions src/docs/WorkStealingDeque.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
WorkStealingDeque{T}()

Concurrent work-stealing "deque" of objects of type `T`.

This is not a full deque in the sense that:

* `push!` and [`trypop!`](@ref) operating at the tail of the collection can
only be executed by a single task.
* [`trypopfirst!`](@ref) (aka steal) for retrieving and removing an element at
the head can be invoked from any tasks. However, there is no `pushfirst!`.

Implementation detail: It implements the dynamic circular work-stealing deque by
Chase and Lev (2005).

# Examples

```julia
julia> using ConcurrentCollections

julia> deque = WorkStealingDeque{Int}();

julia> push!(deque, 1);

julia> push!(deque, 2);

julia> push!(deque, 3);

julia> trypop!(deque)
Some(3)

julia> fetch(Threads.@spawn trypopfirst!(deque))
Some(1)

julia> fetch(Threads.@spawn popfirst!(deque))
2

julia> trypopfirst!(deque) # returns nothing
```
35 changes: 35 additions & 0 deletions src/docs/modify!.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
modify!(f, dict::ConcurrentDict{K,V}, key::K) -> y

Atomically update `key` slot of `dict` using a function `f`.

If `key` does not exist, `f` is called with `nothing`. The call `f(nothing)`
must return either (1) `nothing` to keep the slot unoccupied or (2)
`Some(value::V)` to insert `value`.

If `key` exist, `f` is called with a `ref` such that `ref[]` retrieves the
`value` corresponding to the `key`. The call `f(ref)` must return either (1)
`nothing` to delete the slot, (2) `Some(value′::V)` to insert `value`, (3)
[`Keep(ans)`](@ref ConcurrentCollection.Keep) to return `y = Keep(ans)` from
`modify!`, or (4) [`Delete(ans)`](@ref ConcurrentCollection.Delete) to delete
slot and return a value `y = Delete(ans)` from `modify!`.

The function `f` may be called more than once if multiple tasks try to modify
the dictionary.

# Examples

```julia
julia> using ConcurrentCollections

julia> dict = ConcurrentDict{String,Int}();

julia> modify!(dict, "hello") do _
Some(1)
end
Some(1)

julia> modify!(dict, "hello") do ref
Some(something(ref[]) + 1)
end
Some(2)
```
2 changes: 2 additions & 0 deletions src/docs/tryget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tryget(dict::ConcurrentDict{K,V}, key) -> Some(value::T) or nothing

19 changes: 19 additions & 0 deletions src/docs/trypop!.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
trypop!(collection) -> Some(value::T) or nothing

Try to pop a `value` from the tail of `collection`. Return `Some(value)` if it
is non-empty. Return `nothing` if empty.

# Examples

```julia
julia> using ConcurrentCollections

julia> stack = ConcurrentStack{Int}();

julia> push!(stack, 1);

julia> trypop!(stack)
Some(1)

julia> trypop!(stack) # returns nothing
```
20 changes: 20 additions & 0 deletions src/docs/trypopfirst!.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
trypopfirst!(collection) -> Some(value::T) or nothing


Try to pop a `value` from the head of `collection`. Return `Some(value)` if it
is non-empty. Return `nothing` if empty.

# Examples

```julia
julia> using ConcurrentCollections

julia> queue = ConcurrentQueue{Int}();

julia> push!(queue, 1);

julia> trypopfirst!(queue)
Some(1)

julia> trypopfirst!(queue) # returns nothing
```
19 changes: 19 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,22 @@ function threaded_typed_mapreduce(f, ::Type{T}, op, xs; kw...) where {T}
end
return mapreduce(getindex, op, refs; kw...)
end

function define_docstrings()
docstrings = [:ConcurrentCollections => joinpath(dirname(@__DIR__), "README.md")]
docsdir = joinpath(@__DIR__, "docs")
for filename in readdir(docsdir)
stem, ext = splitext(filename)
ext == ".md" || continue
name = Symbol(stem)
name in names(ConcurrentCollections, all=true) || continue
push!(docstrings, name => joinpath(docsdir, filename))
end
for (name, path) in docstrings
include_dependency(path)
doc = read(path, String)
doc = replace(doc, r"^```julia"m => "```jldoctest $name")
doc = replace(doc, "<kbd>TAB</kbd>" => "_TAB_")
@eval ConcurrentCollections $Base.@doc $doc $name
end
end
Loading

0 comments on commit de09bb2

Please sign in to comment.