// 
// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 
// 



#ifndef CHARLS_LOSSLESSTRAITS
#define CHARLS_LOSSLESSTRAITS

#include "defaulttraits.h"

//
// optimized trait classes for lossless compression of 8 bit color and 8/16 bit monochrome images.
// This class is assumes MAXVAL correspond to a whole number of bits, and no custom RESET value is set when encoding.
// The point of this is to have the most optimized code for the most common and most demanding scenario. 

template<typename sample, int32_t bitsperpixel>
struct LosslessTraitsImplT 
{
    typedef sample SAMPLE;
    enum
    {
        NEAR  = 0,
        bpp   = bitsperpixel,
        qbpp  = bitsperpixel,
        RANGE = (1 << bpp),
        MAXVAL= (1 << bpp) - 1,
        LIMIT = 2 * (bitsperpixel + MAX(8,bitsperpixel)),
        RESET = BASIC_RESET
    };

    static inlinehint int32_t ComputeErrVal(int32_t d)
    {
        return ModuloRange(d);
    }

    static inlinehint bool IsNear(int32_t lhs, int32_t rhs)
    {
        return lhs == rhs;
    }

// The following optimalization is implementation-dependent (works on x86 and ARM, see charlstest). 
#if defined(__clang__) && (__clang_major__ > 7)
     __attribute__((no_sanitize("shift")))
#endif    
    static inlinehint int32_t ModuloRange(int32_t errorValue)
    {
        return int32_t(errorValue << (INT32_BITCOUNT - bpp)) >> (INT32_BITCOUNT - bpp); 
    }

    static inlinehint SAMPLE ComputeReconstructedSample(int32_t Px, int32_t ErrVal)
    {
        return SAMPLE(MAXVAL & (Px + ErrVal)); 
    }

    static inlinehint int32_t CorrectPrediction(int32_t Pxc) 
    {
        if ((Pxc & MAXVAL) == Pxc)
            return Pxc;

        return (~(Pxc >> (INT32_BITCOUNT-1))) & MAXVAL;
    }
};


template<typename SAMPLE, int32_t bpp>
struct LosslessTraitsT : LosslessTraitsImplT<SAMPLE, bpp> 
{
    typedef SAMPLE PIXEL;
};


template<>
struct LosslessTraitsT<uint8_t, 8> : LosslessTraitsImplT<uint8_t, 8>
{
    typedef SAMPLE PIXEL;

    static inlinehint signed char ModRange(int32_t Errval) 
    {
        return static_cast<signed char>(Errval);
    }

    static inlinehint int32_t ComputeErrVal(int32_t d)
    {
        return static_cast<signed char>(d);
    }

    static inlinehint uint8_t ComputeReconstructedSample(int32_t Px, int32_t ErrVal)
    {
        return uint8_t(Px + ErrVal);
    }
};


template<>
struct LosslessTraitsT<uint16_t, 16> : LosslessTraitsImplT<uint16_t, 16>
{
    typedef SAMPLE PIXEL;

    static inlinehint short ModRange(int32_t Errval) 
    {
        return short(Errval);
    }

    static inlinehint int32_t ComputeErrVal(int32_t d)
    {
        return short(d);
    }

    static inlinehint SAMPLE ComputeReconstructedSample(int32_t Px, int32_t ErrVal)
    {
        return SAMPLE(Px + ErrVal);
    }
};


template<typename SAMPLE, int32_t bpp>
struct LosslessTraitsT<Triplet<SAMPLE>, bpp> : LosslessTraitsImplT<SAMPLE, bpp>
{
    typedef Triplet<SAMPLE> PIXEL;

    static inlinehint bool IsNear(int32_t lhs, int32_t rhs)
    {
        return lhs == rhs;
    }

    static inlinehint bool IsNear(PIXEL lhs, PIXEL rhs)
    {
        return lhs == rhs;
    }

    static inlinehint SAMPLE ComputeReconstructedSample(int32_t Px, int32_t ErrVal)
    {
        return SAMPLE(Px + ErrVal);
    }
};

#endif
