/*---------------------------------------------------------------------------
  Copyright 2021-2021, Microsoft Research, Daan Leijen.

    This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

/*
Experimental: Parallel tasks.

Note: very experimental and may not work as intended :-)
See ``test/bench/koka/binarytrees.kk`` for example usage.
*/
module std/os/taskstd/os/task

import std/num/int32std/num/int32

// A `:promise<a>` can be `await`ed for a result.
abstract struct promisestd/os/task/promise: V -> V<aa: V>
  promisestd/os/task/promise/promise: forall<a> (promise : promise<a>) -> any : anystd/core/types/any: V

noinline extern unsafe_taskstd/os/task/unsafe_task: forall<a> (work : () -> a) -> any( workwork: () -> $142 : () -> astd/core/types/total: E ) : anystd/core/types/any: V
  c "kk_task_schedule"

noinline extern unsafe_awaitstd/os/task/unsafe_await: forall<a> (p : any) -> a( pp: any : anystd/core/types/any: V ) : astd/core/types/total: E
  c "kk_promise_get"

extern prim-task-set-default-concurrencystd/os/task/prim-task-set-default-concurrency: (thread-count : ssize_t) -> ioc ()( thread-countthread-count: ssize_t : ssize_tstd/core/types/ssize_t: V  ) : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V
  c "kk_task_set_default_concurrency"

pub fun task-set-default-concurrencystd/os/task/task-set-default-concurrency: (thread-count : int) -> ioc ()( thread-countthread-count: int : intstd/core/types/int: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V
  prim-task-set-default-concurrencystd/os/task/prim-task-set-default-concurrency: (thread-count : ssize_t) -> ioc ()( thread-countthread-count: int.ssize_tstd/core/int/ssize_t: (i : int) -> ioc ssize_t )


// Spark a pure computation in a separate thread of control.
pub noinline fun taskstd/os/task/task: forall<a> (work : () -> a) -> promise<a>( workwork: () -> $205 : () -> astd/core/types/total: E )result: -> total promise<230> : promisestd/os/task/promise: V -> V<aa: V>
  Promisestd/os/task/Promise: forall<a> (promise : any) -> promise<a>( unsafe_taskstd/os/task/unsafe_task: (work : () -> $205) -> any( workwork: () -> $205 ) )

// Await the result of a promise.
pub fun awaitstd/os/task/await: forall<a> (p : promise<a>) -> a( pp: promise<$235> : promisestd/os/task/promise: V -> V<aa: V> )result: -> total 257 : astd/core/types/total: E
  unsafe_awaitstd/os/task/unsafe_await: (p : any) -> $235( pp: promise<$235>.promisestd/os/task/promise/promise: (promise : promise<$235>) -> any )

// Await the result of a list of promises.
pub fun list/awaitstd/os/task/list/await: forall<a> (ps : list<promise<a>>) -> list<a>( psps: list<promise<$262>> : liststd/core/types/list: V -> V<promisestd/os/task/promise: V -> V<aa: V>> )result: -> total list<325> : liststd/core/types/list: V -> V<aa: V>
  psps: list<promise<$262>>.mapstd/core/list/map: (xs : list<promise<$262>>, f : (promise<$262>) -> $262) -> list<$262>(awaitstd/os/task/await: (p : promise<$262>) -> $262)

// Run a list of pure computations in parallel.
pub fun parallelstd/os/task/parallel: forall<a> (xs : list<() -> a>) -> list<a>( xsxs: list<() -> $330> : liststd/core/types/list: V -> V<() -> astd/core/types/total: E> )result: -> total list<439> : liststd/core/types/list: V -> V<aa: V>
  xsxs: list<() -> $330>.mapstd/core/list/map: (xs : list<() -> $330>, f : (() -> $330) -> promise<$330>) -> list<promise<$330>>( taskstd/os/task/task: (work : () -> $330) -> promise<$330> ).awaitstd/os/task/list/await: (ps : list<promise<$330>>) -> list<$330>


/*
noinline extern unsafe_task_n( count : ssize_t, stride : ssize_t, work : () -> pure a, combine : (a,a) -> a ) : pure any
  c "kk_task_schedule_n"

pub noinline fun taskn( count : int, stride : int, work : () -> pure a, combine : (a,a) -> total a ) : pure promise<a>
  Promise( unsafe_task_n( count.ssize_t, stride.ssize_t, work, combine ) )

*/

// ---------------------------------------------------------
// LVar's
// Note: currently unsafe in the pure effect!! needs work

abstract struct lvarstd/os/task/lvar: V -> V<aa: V>
  lvstd/os/task/lvar/lv: forall<a> (lvar : lvar<a>) -> any : anystd/core/types/any: V

noinline extern unsafe-lvarstd/os/task/unsafe-lvar: forall<a> (init : a) -> any( initinit: $494 : aa: V ) : anystd/core/types/any: V
  c "kk_lvar_alloc"

noinline extern unsafe-putstd/os/task/unsafe-put: forall<a> (lvar : any, x : a, monotonic-combine : (a, a) -> a) -> ()( lvarlvar: any : anystd/core/types/any: V, xx: $514 : aa: V, monotonic-combinemonotonic-combine: ($514, $514) -> $514 : (aa: V,aa: V) -> astd/core/types/total: E ) : (std/core/types/unit: V)std/core/types/unit: V
  c "kk_lvar_put"

noinline extern unsafe-getstd/os/task/unsafe-get: forall<a> (lvar : any, bot : a, is-gte : (a, a) -> int32) -> ndet a( lvarlvar: any : anystd/core/types/any: V, botbot: $538 : aa: V, is-gteis-gte: ($538, $538) -> int32 : (aa: V,aa: V) -> int32std/core/types/int32: V ) : ndetstd/core/types/ndet: X aa: V
  c "kk_lvar_get"

pub noinline fun lvarstd/os/task/lvar: forall<a> (init : a) -> lvar<a>( initinit: $562 : aa: V )result: -> total lvar<584> : lvarstd/os/task/lvar: V -> V<aa: V>
  Lvarstd/os/task/Lvar: forall<a> (lv : any) -> lvar<a>( unsafe-lvarstd/os/task/unsafe-lvar: (init : $562) -> any(initinit: $562) )

pub fun putstd/os/task/put: forall<a> (lvar : lvar<a>, x : a, monotonic-combine : (a, a) -> a) -> ()( lvarlvar: lvar<$589> : lvarstd/os/task/lvar: V -> V<aa: V>, xx: $589 : aa: V, monotonic-combinemonotonic-combine: ($589, $589) -> $589 : (aa: V,aa: V) -> astd/core/types/total: E )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V
  unsafe-putstd/os/task/unsafe-put: (lvar : any, x : $589, monotonic-combine : ($589, $589) -> $589) -> ()( lvarlvar: lvar<$589>.lvstd/os/task/lvar/lv: (lvar : lvar<$589>) -> any, xx: $589, monotonic-combinemonotonic-combine: ($589, $589) -> $589 )

pub fun getstd/os/task/get: forall<a> (lvar : lvar<a>, bot : a, is-gte : (a, a) -> bool) -> ndet a( lvarlvar: lvar<$620> : lvarstd/os/task/lvar: V -> V<aa: V>, botbot: $620 : aa: V, is-gteis-gte: ($620, $620) -> bool: (aa: V,aa: V) -> boolstd/core/types/bool: V )result: -> ndet 656 : ndetstd/core/types/ndet: X aa: V
  unsafe-getstd/os/task/unsafe-get: (lvar : any, bot : $620, is-gte : ($620, $620) -> int32) -> ndet $620( lvarlvar: lvar<$620>.lvstd/os/task/lvar/lv: (lvar : lvar<$620>) -> ndet any, botbot: $620, fnfn: (x : $620, y : $620) -> int32(xx: $620,yy: $620){ if (is-gteis-gte: ($620, $620) -> bool(xx: $620,yy: $620)) then onestd/num/int32/one: int32 else zerostd/num/int32/zero: int32 } )