


//
// eachValue, mapValues, foldValues, weaveValues,
// takeValues, dropValues
//

inline eachValue(fn, ..xs) {
    ..for (x in xs) {
        fn(x);
    }
}

define mapValues;
inline overload mapValues(fn, forward x, forward ..xs)
    = forward ..fn(x), ..mapValues(fn, ..xs);
inline overload mapValues(fn) = ;

private define _mapIndexedValues;
[n] inline overload _mapIndexedValues(fn, static n, forward x, forward ..xs)
    = forward ..fn(x, n), .._mapIndexedValues(fn, static n+1, ..xs);
[n] inline overload _mapIndexedValues(fn, static n) = ;

mapIndexedValues(fn, forward ..values) = forward .._mapIndexedValues(fn, static 0, ..values);

define foldValues;
inline overload foldValues(fn, forward x, forward ..xs)
    = fn(x, foldValues(fn, ..xs));
inline overload foldValues(fn, forward x) = forward x;

define foldlValues;
inline overload foldlValues(fn, forward x1, forward x2, forward ..xs)
    = foldlValues(fn, fn(x1, x2), ..xs);
inline overload foldlValues(fn, forward x) = forward x;

define weaveValues;
inline overload weaveValues(between, forward x, forward ..xs)
    = forward x, between, ..weaveValues(between, ..xs);
inline overload weaveValues(between, forward x, forward y)
    = forward x, between, y;
inline overload weaveValues(between, forward x) = forward x;
inline overload weaveValues(between) = ;

define takeValues;
[i] inline overload takeValues(static i, forward x, forward ..xs)
    = forward x, ..takeValues(static i-1, ..xs);
[i | i == 0] inline overload takeValues(static i, forward ..xs) = ;
[i] inline overload takeValues(static i) = ;

define dropValues;
[i] inline overload dropValues(static i, forward x, forward ..xs)
    = forward ..dropValues(static i-1, ..xs);
[i | i == 0] inline overload dropValues(static i, forward ..xs) = forward ..xs;
[i] inline overload dropValues(static i) = ;



//
// countValues, nthValue, firstValue
//

countValues(..args) {
    var n = 0;
    ..for (x in args)
        n += 1;
    return n;
}

define countOccurrences;
inline overload countOccurrences(value) = 0;
[value1, value2]
inline overload countOccurrences(static value1, static value2, forward ..xs)
    = countOccurrences(value1, ..xs);
[value]
inline overload countOccurrences(static value, static value, forward ..xs)
    = 1 + countOccurrences(value, ..xs);

define nthValue;
[i] inline overload nthValue(static i, forward a, forward ..b)
    = forward nthValue(static i-1, ..b);
[i | i == 0] inline overload nthValue(static i, forward a, ..b) = forward a;

inline firstValue(forward a, ..rest) = forward a;

inline restValues(a, forward ..rest) = forward ..rest;

inline lastValue(a, forward ..rest) = forward lastValue(..rest);
overload lastValue(forward a) = forward a;



//
// replicateValue, allValues?, anyValues?, equalValues?, inValues?
//

[n]
inline replicateValue(a, static n) = a, ..replicateValue(a, static n-1);
inline overload replicateValue(a, static 0) = ;

inline allValues?(pred, ..rest) {
    ..for (x in rest) {
        if (not pred(x))
            return false;
    }
    return true;
}

inline anyValues?(pred, ..rest) {
    ..for (x in rest) {
        if (pred(x))
            return true;
    }
    return false;
}

inline equalValues?(a, ..rest) = allValues?(x => a == x, ..rest);

inValues?(a, ..rest) = anyValues?(x => a == x, ..rest);



//
// capture/forward values
// 

// captureValue, forwardValue, capturedRef

private record CapturedLValue[T] (
    ptr : Pointer[T]
);

define captureValue;
inline overload captureValue(rvalue x) = move(x);
inline overload captureValue(ref x) = CapturedLValue(&x);

define forwardValue;
inline overload forwardValue(x) = move(x);
[T] inline overload forwardValue(x:CapturedLValue[T]) = ref x.ptr^;

define capturedRef;
inline overload capturedRef(x) = ref x;
[T] inline overload capturedRef(x:CapturedLValue[T]) = ref x.ptr^;

// captureValues, forwardValues, capturedRefs

inline captureValues(forward ..args) = Tuple(..mapValues(captureValue, ..args));

[..T]
inline forwardValues(x:Tuple[..T]) =
    forward ..mapValues(forwardValue, ..unpackTupleRef(x));

[..T]
inline capturedRefs(x:Tuple[..T]) =
    forward ..mapValues(capturedRef, ..unpackTupleRef(x));



//
// expand values from sequence or iterator 
//
[S, n | Sequence?(S)]
sequenceValues(seq: S, static n) = forward ..iteratorValues(iterator(seq), static n);

[I | Iterator?(I)]
iteratorValues(iter: I, static 0) = ;
[I, n | Iterator?(I) and n > 0]
overload iteratorValues(iter: I, static n)
    = forward next(iter), ..iteratorValues(iter, static n-1);



//
// iterate over two sets of values in tandem
//
[n | n > 0] withoutNthValue(static n, forward value, forward ..values)
    = forward value, ..withoutNthValue(static n-1, ..values);
overload withoutNthValue(static 0, forward value, forward ..values)
    = forward ..values;

[n | n > 0] eachValue2(fn, static n, forward x, forward ..xs) {
    fn(x, nthValue(static n-1, ..xs));
    return ..eachValue2(fn, static n-1, ..withoutNthValue(static n-1, ..xs));
}
overload eachValue2(fn, static 0, forward ..xs) { }

[n | n > 0] mapValues2(fn, static n, forward x, forward ..xs)
    = forward fn(x, nthValue(static n-1, ..xs)),
      ..mapValues2(fn, static n-1, ..withoutNthValue(static n-1, ..xs));
overload mapValues2(fn, static 0, forward ..xs) = ;



//
// treat multiple static tuple values as key-values pairs
//

[key]
assocValue(static key, kv, forward ..kvs) = forward ..assocValue(static key, ..kvs);

[key, ..T]
overload assocValue(static key, forward kv: Tuple[Static[key], ..T], ..kvs)
    = forward ..restValues(..unpack(kv));

[key]
assocValue?(static key) = false;
[key]
overload assocValue?(static key, kv, ..kvs) = assocValue?(key, ..kvs);
[key, ..T]
overload assocValue?(static key, kv: Tuple[Static[key], ..T], ..kvs) = true;

[key]
assocCountValues(static key) = -1;
[key]
overload assocCountValues(static key, kv, ..kvs) = assocCountValues(key, ..kvs);
[key, ..T]
overload assocCountValues(static key, kv: Tuple[Static[key], ..T], ..kvs) = countValues(..T);



//
// find the index of a value within a value list
//

[n, value, other]
private _valueIndex(static n, static value, static other, ..etc)
    = _valueIndex(static n+1, static value, ..etc);
[n, value]
overload _valueIndex(static n, static value, static value, ..etc) = n;
[value]
valueIndex(static value, ..etc) = _valueIndex(static 0, static value, ..etc);


//
// generate a list of non-static integers
[n] integers(static n) = ..mapValues(unwrapStatic, ..staticIntegers(static n));
