/**
 * This header is used internally by all current supported SIMD extensions,
 * except for AVX512.
 */
#ifndef NPY_SIMD
    #error "Not a standalone header, use simd/simd.h instead"
#endif

#ifndef _NPY_SIMD_EMULATE_MASKOP_H
#define _NPY_SIMD_EMULATE_MASKOP_H

/**
 * Implements conditional addition and subtraction.
 * e.g. npyv_ifadd_f32(mask, a, b, c) -> mask ? a + b : c
 * e.g. npyv_ifsub_f32(mask, a, b, c) -> mask ? a - b : c
 */
#define NPYV_IMPL_EMULATE_MASK_ADDSUB(SFX, BSFX)              \
    NPY_FINLINE npyv_##SFX npyv_ifadd_##SFX                   \
    (npyv_##BSFX m, npyv_##SFX a, npyv_##SFX b, npyv_##SFX c) \
    {                                                         \
        npyv_##SFX add = npyv_add_##SFX(a, b);                \
        return npyv_select_##SFX(m, add, c);                  \
    }                                                         \
    NPY_FINLINE npyv_##SFX npyv_ifsub_##SFX                   \
    (npyv_##BSFX m, npyv_##SFX a, npyv_##SFX b, npyv_##SFX c) \
    {                                                         \
        npyv_##SFX sub = npyv_sub_##SFX(a, b);                \
        return npyv_select_##SFX(m, sub, c);                  \
    }

NPYV_IMPL_EMULATE_MASK_ADDSUB(u8,  b8)
NPYV_IMPL_EMULATE_MASK_ADDSUB(s8,  b8)
NPYV_IMPL_EMULATE_MASK_ADDSUB(u16, b16)
NPYV_IMPL_EMULATE_MASK_ADDSUB(s16, b16)
NPYV_IMPL_EMULATE_MASK_ADDSUB(u32, b32)
NPYV_IMPL_EMULATE_MASK_ADDSUB(s32, b32)
NPYV_IMPL_EMULATE_MASK_ADDSUB(u64, b64)
NPYV_IMPL_EMULATE_MASK_ADDSUB(s64, b64)
#if NPY_SIMD_F32
    NPYV_IMPL_EMULATE_MASK_ADDSUB(f32, b32)
#endif
#if NPY_SIMD_F64
    NPYV_IMPL_EMULATE_MASK_ADDSUB(f64, b64)
#endif
#if NPY_SIMD_F32
    // conditional division, m ? a / b : c
    NPY_FINLINE npyv_f32
    npyv_ifdiv_f32(npyv_b32 m, npyv_f32 a, npyv_f32 b, npyv_f32 c)
    {
        const npyv_f32 one = npyv_setall_f32(1.0f);
        npyv_f32 div = npyv_div_f32(a, npyv_select_f32(m, b, one));
        return npyv_select_f32(m, div, c);
    }
    // conditional division, m ? a / b : 0
    NPY_FINLINE npyv_f32
    npyv_ifdivz_f32(npyv_b32 m, npyv_f32 a, npyv_f32 b)
    {
        const npyv_f32 zero = npyv_zero_f32();
        return npyv_ifdiv_f32(m, a, b, zero);
    }
#endif
#if NPY_SIMD_F64
    // conditional division, m ? a / b : c
    NPY_FINLINE npyv_f64
    npyv_ifdiv_f64(npyv_b64 m, npyv_f64 a, npyv_f64 b, npyv_f64 c)
    {
        const npyv_f64 one = npyv_setall_f64(1.0);
        npyv_f64 div = npyv_div_f64(a, npyv_select_f64(m, b, one));
        return npyv_select_f64(m, div, c);
    }
    // conditional division, m ? a / b : 0
    NPY_FINLINE npyv_f64
    npyv_ifdivz_f64(npyv_b64 m, npyv_f64 a, npyv_f64 b)
    {
        const npyv_f64 zero = npyv_zero_f64();
        return npyv_ifdiv_f64(m, a, b, zero);
    }
#endif

#endif // _NPY_SIMD_EMULATE_MASKOP_H
