#!/usr/bin/env ol
; some global test constants
; win64: minimal 5 (4 ints same 4 floats, 1 stack)
; nix64: minimal 15 (6 ints, 8 floats, 1 stack)
; x86:   minimal 1 (1 stack)
; arm64: minimal 17 (8 ints, 8 floats, 1 stack)
; arm32: minimal 21 (4 nums, 16 floats, 1 stack) ?
; mips64: minimal ?

(import (otus ffi))

(define this (load-dynamic-library #f))
(define (copy x) (vm:cast x (type x)))

;; legend:
;;    C - unsigned char
;;    S - unsigned short
;;    I - unsigned int
;;    L - unsigned long
;;    Q - unsigned long long
;;    c - signed char
;;    s - signed short
;;    i - signed int
;;    l - signed long
;;    q - signed long long
;;    f - float
;;    d - double

; short type names
(define void   fft-void)
(define uchar  fft-unsigned-char)
(define ushort fft-unsigned-short)
(define uint   fft-unsigned-int)
(define ullong fft-unsigned-long-long)
(define char   fft-signed-char)
(define short  fft-signed-short)
(define int    fft-signed-int)
(define llong  fft-signed-long-long)
(define float  fft-float)
(define double fft-double)

;; note:
;;    fft-char is signed by default
;;    we don't support rational numbers as fft&
(print "Notes:
 * no tests for type 'long' because 'long' is either 'int' or 'long long' depends on OS
   and is completely covered by other tests ('int' and 'long long').
 * type legend: 'c' for char, 's' for short, 'i' for int, 'q' for long long,
   capital chars for unsigned prefixes;  'f' for float, 'd' for double.
 * output inside {{ .. }} is native code output")

; global numeric constants
(define INT8_MIN -128)
(define INT8_MAX +127)

(define INT16_MIN -32768)
(define INT16_MAX +32767)

(define INT32_MIN -2147483648)
(define INT32_MAX +2147483647)

(define INT64_MIN -9223372036854775807)
(define INT64_MAX +9223372036854775807)

(define UINT8_MAX  255)
(define UINT16_MAX 65535)
(define UINT32_MAX 4294967295)
(define UINT64_MAX 18446744073709551615)

(define MAGIC8  #x01)
(define MAGIC16 #x0203)
(define MAGIC32 #x04050607)
(define MAGIC64 #x08090A0B0C0D0E0F)

;; (define Pn '( ; 114 prime numbers
(define primes '(
       1     2     3     5     7    11   101   131   151   181   191   313
     353   373   383   727   757   787   797   919   929 10301 10501 10601
   11311 11411 12421 12721 12821 13331 13831 13931 14341 14741 15451 15551
   16061 16361 16561 16661 17471 17971 18181 18481 19391 19891 19991 30103
   30203 30403 30703 30803 31013 31513 32323 32423 33533 34543 34843 35053
   35153 35353 35753 36263 36563 37273 37573 38083 38183 38783 39293 70207
   70507 70607 71317 71917 72227 72727 73037 73237 73637 74047 74747 75557
   76367 76667 77377 77477 77977 78487 78787 78887 79397 79697 79997 90709
   91019 93139 93239 93739 94049 94349 94649 94849 94949 95959 96269 96469
   96769 97379 97579 97879 98389 98689
))
;; (define Sn ; 114 consecutive numbers 1..n
;;    (iota 114 1))

(define (try tag function args)
   (for-each display (list "   " (cons tag args) " --> "))
   (let ((out (apply function args)))
      (print " = " out)))

;; (import (scheme dynamic-bindings))

; ----------------------------------------------------------------
; templates
(define (|cc..c(n)2c| char n)
   (string-append (apply string-append (repeat char n)) "2" char))
(define (|v_cc..c(n)| char n)
   (string-append "void_" (apply string-append (repeat char n))))

(define (|type a1, type a2, .., type an| typename n)
   (apply string-append
      (cons* typename " a1"
         (map (lambda (i)
               (string-append ", " typename " a" (number->string i)))
            (iota (- n 1) 2)) )))

(define (|%d %d .. %d(n)| format n)
   (apply string-append
      (cons* format
         (map (lambda (i)
               (string-append " " format))
            (iota (- n 1) 2)) )))

(define (|a1 + a2 + .. + an| n)
   (apply string-append
      (cons* "a1"
         (map (lambda (i)
               (string-append " + a" (number->string i)))
            (iota (- n 1) 2)) )))

(define (|a1, a2, .., an| n)
   (apply string-append
      (cons* "a1"
         (map (lambda (i)
               (string-append ", a" (number->string i)))
            (iota (- n 1) 2)) )))

(define (|v_cc..d[i]..c(n)| charA charB i n)
   (string-append "v_" (apply string-append (map (lambda (x) (if (= x i) charB charA)) (iota n 1)))))

(define (|typeA a1, typeA a2, .., typeB b, .., type an| typeA typeB i n)
   (s/^, //
   (apply string-append
      (map (lambda (x)
            (if (= x i)
               (string-append ", " typeB " b")
               (string-append ", " typeA " a" (number->string x))))
         (iota n 1)))))

(define (|%d %d .. %u .. %d(n)| formatA formatB i n)
   (s/^ //
   (apply string-append
      (map (lambda (x)
            (if (= x i)
               (string-append " " formatB)
               (string-append " " formatA)))
         (iota n 1)))))

(define (|a1, a2, .., b , .., aN| i n)
   (s/^, //
   (apply string-append
      (map (lambda (x)
            (if (= x i)
               (string-append ", " " b")
               (string-append ", " " a" (number->string x))))
         (iota n 1)))))
