Skip to content
Snippets Groups Projects
Contexts.h 38.87 KiB
/* The copyright in this software is being made available under the BSD
 * License, included below. This software may be subject to other third party
 * and contributor rights, including patent rights, and no such rights are
 * granted under this license.
 *
 * Copyright (c) 2010-2023, ITU/ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

/** \file     Contexts.h
 *  \brief    Classes providing probability descriptions and contexts (header)
 */

#ifndef __CONTEXTS__
#define __CONTEXTS__

#include "CommonDef.h"
#include "Slice.h"

#include <vector>

static constexpr int     PROB_BITS   = 15;   // Nominal number of bits to represent probabilities
#if EC_HIGH_PRECISION
static constexpr int     PROB_BITS_0 = 15;   // Number of bits to represent 1st estimate
static constexpr int     PROB_BITS_1 = 15;   // Number of bits to represent 2nd estimate
#else
static constexpr int     PROB_BITS_0 = 10;   // Number of bits to represent 1st estimate
static constexpr int     PROB_BITS_1 = 14;   // Number of bits to represent 2nd estimate
#endif
static constexpr int     MASK_0      = ~(~0u << PROB_BITS_0) << (PROB_BITS - PROB_BITS_0);
static constexpr int     MASK_1      = ~(~0u << PROB_BITS_1) << (PROB_BITS - PROB_BITS_1);
static constexpr uint8_t DWS         = 8;   // 0x47 Default window sizes
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
static constexpr uint8_t DWE         = 18;  // default weights
static constexpr uint8_t DWO         = 119; // default window offsets
#endif

struct BinFracBits
{
  uint32_t intBits[2];
};


enum BPMType
{
  BPM_Undefined = 0,
  BPM_Std,
  BPM_NUM
};

#if JVET_AG0117_CABAC_SPATIAL_TUNING
struct BinStoreElem
{
  uint8_t  bins;
  uint8_t  count;
  unsigned ctxId;
  
  BinStoreElem(unsigned b, unsigned c) : bins(b), count(1), ctxId(c) {}

  unsigned bin(int i) const
  {
    return (bins >> i) & 1;
  }
  
  void addBin(unsigned bin)
  {
    bins |= bin << count++;
  }
};

typedef std::vector<BinStoreElem> BinStoreVector;

class BinBuffer
{
public:
  BinBuffer() : m_active(false), m_maxSize(0), m_numCtx(0), m_maxBinsPerCtx(0), m_buffer(nullptr) {}
  ~BinBuffer() {}

  void init(int size, int numCtx, int maxBinsPerCtx)
  {
    m_active           = false;
    m_maxSize          = size;
    m_numCtx           = numCtx;
    m_maxBinsPerCtx    = maxBinsPerCtx;
    m_indOfCtxInBuffer = std::vector<int16_t>(numCtx, -1);

    if ( m_maxBinsPerCtx > 8 )
    {
      fprintf(stdout, "Chance type of BinStoreElem/bins to support over 8 bins per context\n");
      exit(0);
    }
  }

  void addBin( unsigned bin, unsigned ctxId )
  {
    if( m_active )
    {
      int bufferInd = m_indOfCtxInBuffer[ctxId];
      
      if( bufferInd >= 0 ) // Already active context type
      {
        BinStoreElem& store = (*m_buffer)[bufferInd];

        if( store.count < m_maxBinsPerCtx ) // Room to add more bins
        {
          store.addBin( bin );
        }
      }
      else if ( m_buffer->size() < m_maxSize ) // Room to add more context types
      {
        m_indOfCtxInBuffer[ctxId] = static_cast<int16_t>(m_buffer->size());
        m_buffer->push_back( BinStoreElem( bin, ctxId ) );
      }
    }
  }
  void clear()           { m_buffer->clear(); std::fill(m_indOfCtxInBuffer.begin(), m_indOfCtxInBuffer.end(), -1); }
  void setActive(bool b) { m_active = b; }
  
  const BinStoreVector* getBinStoreVector() const { return m_buffer; }
  void                  setBinStoreVector(BinStoreVector *bb) { m_buffer = bb; if (bb) clear(); }

private:
  bool                 m_active;
  std::size_t          m_maxSize;
  int                  m_numCtx;
  int                  m_maxBinsPerCtx;
  std::vector<int16_t> m_indOfCtxInBuffer; // Only used in active CTU for convenience (8 bit enough)
  BinStoreVector*      m_buffer;
};

class BinBufferer
{
public:
  BinBufferer(): m_binBuffer () {}

  void             setBinBufferActive ( bool b )             { m_binBuffer.setActive(b); }
  void             setBinBuffer       ( BinStoreVector *bb ) { m_binBuffer.setBinStoreVector(bb); }
  const BinStoreVector* getBinBuffer  ( )             const  { return m_binBuffer.getBinStoreVector(); }
  void             initBufferer(int size, int numCtx, int maxBinsPerCtx) { m_binBuffer.init( size, numCtx, maxBinsPerCtx); }
  virtual void     updateCtxs         ( BinStoreVector *bb ) = 0;

protected:
  BinBuffer m_binBuffer;
};
#endif

class ProbModelTables
{
protected:
#if EC_HIGH_PRECISION
	static const BinFracBits m_binFracBits[512];
#else
  static const BinFracBits m_binFracBits[256];
#endif
  static const uint8_t      m_RenormTable_32  [ 32];          // Std         MP   MPI
};

class BinProbModelBase : public ProbModelTables
{
public:
  BinProbModelBase () {}
  ~BinProbModelBase() {}
  static uint32_t estFracBitsEP ()                    { return  (       1 << SCALE_BITS ); }
  static uint32_t estFracBitsEP ( unsigned numBins )  { return  ( numBins << SCALE_BITS ); }
};

#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
const uint8_t weightedAdaptRate[5] = { 10, 12, 16, 20, 22 };
#endif

class BinProbModel_Std : public BinProbModelBase
{
public:
  BinProbModel_Std()
  {
    uint16_t half = 1 << (PROB_BITS - 1);
    m_state[0]    = half;
    m_state[1]    = half;
    m_rate        = DWS;
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
    m_weight        = DWE;
    m_stateUsed[0]  = half;
    m_stateUsed[1]  = half;
    m_rateOffset[0] = DWO;
    m_rateOffset[1] = DWO;
#endif

  }
  ~BinProbModel_Std ()                {}
public:
  void            init              ( int qp, int initId );
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  void update(unsigned bin)
  {
    int rate0 = m_rate >> 4;
    int rate1 = m_rate & 15;

    auto ws = m_rateOffset[bin];

    int rateUsed0 = std::max( 2, rate0 + (ws >> 4) - ADJUSTMENT_RANGE );
    int rateUsed1 = std::max( 2, rate1 + (ws & 15) - ADJUSTMENT_RANGE );

    m_stateUsed[0] = m_state[0] - ((m_state[0] >> rateUsed0) & MASK_0);
    m_stateUsed[1] = m_state[1] - ((m_state[1] >> rateUsed1) & MASK_1);

    m_state[0] -= (m_state[0] >> rate0) & MASK_0;
    m_state[1] -= (m_state[1] >> rate1) & MASK_1;

    if (bin)
    {
      m_stateUsed[0] += (0x7FFFU >> rateUsed0) & MASK_0;
      m_stateUsed[1] += (0x7FFFU >> rateUsed1) & MASK_1;

      m_state[0] += (0x7fffu >> rate0) & MASK_0;
      m_state[1] += (0x7fffu >> rate1) & MASK_1;
    }
  }
#if JVET_AG0117_CABAC_SPATIAL_TUNING
  void updateShortWin(unsigned bin)
  {
    int rate0     = m_rate >> 4;
    auto ws       = m_rateOffset[bin];
    int rateUsed0 = std::max( 2, rate0 + (ws >> 4) - ADJUSTMENT_RANGE );

    m_stateUsed[0] = m_state[0] - ((m_state[0] >> rateUsed0) & MASK_0);
    m_state[0]    -= (m_state[0] >> rate0) & MASK_0;

    if (bin)
    {
      m_stateUsed[0] += (0x7FFFU >> rateUsed0) & MASK_0;
      m_state[0]     += (0x7fffu >> rate0) & MASK_0;
    }
  }
#endif
#else
  void update(unsigned bin)
  {
    int rate0 = m_rate >> 4;
    int rate1 = m_rate & 15;

    m_state[0] -= (m_state[0] >> rate0) & MASK_0;
    m_state[1] -= (m_state[1] >> rate1) & MASK_1;
    if (bin)
    {
      m_state[0] += (0x7fffu >> rate0) & MASK_0;
      m_state[1] += (0x7fffu >> rate1) & MASK_1;
    }
  }
#if JVET_AG0117_CABAC_SPATIAL_TUNING
  void updateShortWin(unsigned bin)
  {
    int rate0 = m_rate >> 4;

    m_state[0] -= (m_state[0] >> rate0) & MASK_0;
    
    if (bin)
    {
      m_state[0] += (0x7fffu >> rate0) & MASK_0;
    }
  }
#endif
#endif
  void setLog2WindowSize(uint8_t log2WindowSize)
  {
    int rate0 = 2 + ((log2WindowSize >> 2) & 3);
    int rate1 = 3 + rate0 + (log2WindowSize & 3);
    m_rate    = 16 * rate0 + rate1;
    CHECK(rate1 > 9, "Second window size is too large!");
  }
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  void     setAdaptRateWeight( uint8_t weight ) { m_weight = weight; }
  uint8_t  getAdaptRateWeight() const           { return m_weight; }
  void     setWinSizes( uint8_t rate )          { m_rate = rate; }
  uint8_t  getWinSizes() const                  { return m_rate; }
  void     setAdaptRateOffset(uint8_t rateOffset, bool bin ) { m_rateOffset[bin] = rateOffset;}
#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
  uint8_t  getAdaptRateOffset( bool bin ) const { return m_rateOffset[bin]; }
#endif
#endif

  void estFracBitsUpdate(unsigned bin, uint64_t &b)
  {
    b += estFracBits(bin);
    update(bin);
  }

  uint32_t        estFracBits(unsigned bin) const { return getFracBitsArray().intBits[bin]; }
  static uint32_t estFracBitsTrm(unsigned bin) { return (bin ? 0x3bfbb : 0x0010c); }
#if EC_HIGH_PRECISION
	BinFracBits     getFracBitsArray() const { return m_binFracBits[state_est()]; }
#else
  BinFracBits     getFracBitsArray() const { return m_binFracBits[state()]; }
#endif
public:
#if EC_HIGH_PRECISION
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  uint16_t        state_est() const
  {
    uint8_t  wIdx0 = (m_weight >> 3);
    uint8_t  wIdx1 = (m_weight & 0x07);
    uint32_t w0 = weightedAdaptRate[wIdx0];
    uint32_t w1 = weightedAdaptRate[wIdx1];
    uint32_t pd;
    if( (w0 + w1) <= 32 )
    {
      pd = (uint32_t( m_stateUsed[0] ) * w0 + uint32_t( m_stateUsed[1] ) * w1) >> 11;
    }
    else
    {
      pd = (uint32_t( m_stateUsed[0] ) * w0 + uint32_t( m_stateUsed[1] ) * w1) >> 12;
    }
    return uint16_t( pd );
  }
  uint16_t       state() const
  {
    uint8_t  wIdx0 = (m_weight >> 3);
    uint8_t  wIdx1 = (m_weight & 0x07);
    uint32_t w0 = weightedAdaptRate[wIdx0];
    uint32_t w1 = weightedAdaptRate[wIdx1];
    uint32_t pd;
    if( (w0 + w1) <= 32 )
    {
      pd = (uint32_t( m_stateUsed[0] ) * w0 + uint32_t( m_stateUsed[1] ) * w1) >> 5;
    }
    else
    {
      pd = (uint32_t( m_stateUsed[0] ) * w0 + uint32_t( m_stateUsed[1] ) * w1) >> 6;
    }
    return uint16_t( pd );
  }
#else
  uint16_t state_est() const { return (m_state[0] + m_state[1]) >> 7; }
  uint16_t state() const { return (m_state[0] + m_state[1]) >> 1; }
#endif

	uint8_t mps() const { return state() >> 14; }
	uint8_t getLPS(unsigned range) const
	{
		uint16_t q = state();
    if( q & 0x4000 )
    {
      q = q ^ 0x7fff;
    }
		return ((range * (q >> 6)) >> 9) + 1;
	}
#else
  uint8_t state() const { return (m_state[0] + m_state[1]) >> 8; }
  uint8_t mps() const { return state() >> 7; }
  uint8_t getLPS(unsigned range) const
  {
    uint16_t q = state();
    if (q & 0x80)
      q = q ^ 0xff;
    return ((q >> 2) * (range >> 5) >> 1) + 4;
  }
#endif
  static uint8_t  getRenormBitsLPS  ( unsigned LPS )                    { return    m_RenormTable_32  [LPS>>3]; }
  static uint8_t  getRenormBitsRange( unsigned range )                  { return    1; }
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  std::pair<uint16_t, uint16_t> getState() const { return std::pair<uint16_t, uint16_t>(m_state[0], m_state[1]); }

  void setState( std::pair<uint16_t, uint16_t> pState )
  {
    m_state[0] = pState.first;
    m_state[1] = pState.second;
    m_stateUsed[0] = m_state[0];
    m_stateUsed[1] = m_state[1];
  }
#else
  uint16_t getState() const { return m_state[0] + m_state[1]; }
  void     setState(uint16_t pState)
  {
    m_state[0] = (pState >> 1) & MASK_0;
    m_state[1] = (pState >> 1) & MASK_1;
  }
#endif
public:
  uint64_t estFracExcessBits(const BinProbModel_Std &r) const
  {
#if EC_HIGH_PRECISION
		int n = 2 * state_est() + 1;
		return ((1024 - n) * r.estFracBits(0) + n * r.estFracBits(1) + 512) >> 10;
#else
    int n = 2 * state() + 1;
    return ((512 - n) * r.estFracBits(0) + n * r.estFracBits(1) + 256) >> 9;
#endif
  }

private:
  uint16_t m_state[2];
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT 
  uint16_t m_stateUsed[2];
  uint8_t  m_rateOffset[2];
  uint8_t  m_weight;
#endif
  uint8_t  m_rate;
};



class CtxSet
{
public:
  CtxSet( uint16_t offset, uint16_t size ) : Offset( offset ), Size( size ) {}
  CtxSet( const CtxSet& ctxSet ) : Offset( ctxSet.Offset ), Size( ctxSet.Size ) {}
  CtxSet( std::initializer_list<CtxSet> ctxSets );
public:
  uint16_t  operator()  ()  const
  {
    return Offset;
  }
  uint16_t  operator()  ( uint16_t inc )  const
  {
    CHECKD( inc >= Size, "Specified context increment (" << inc << ") exceed range of context set [0;" << Size - 1 << "]." );
    return Offset + inc;
  }
  bool operator== ( const CtxSet& ctxSet ) const
  {
    return ( Offset == ctxSet.Offset && Size == ctxSet.Size );
  }
  bool operator!= ( const CtxSet& ctxSet ) const
  {
    return ( Offset != ctxSet.Offset || Size != ctxSet.Size );
  }
public:
  uint16_t  Offset;
  uint16_t  Size;
};



class ContextSetCfg
{
public:
  // context sets: specify offset and size
  static const CtxSet   SplitFlag;
  static const CtxSet   SplitQtFlag;
  static const CtxSet   SplitHvFlag;
  static const CtxSet   Split12Flag;
#if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
  static const CtxSet   ModeConsFlag;
#endif
  static const CtxSet   SkipFlag;
  static const CtxSet   MergeFlag;
#if JVET_AG0276_LIC_FLAG_SIGNALING
  static const CtxSet   MergeFlagOppositeLic;
  static const CtxSet   TmMergeFlagOppositeLic;
  static const CtxSet   AffineFlagOppositeLic;
#endif
  static const CtxSet   RegularMergeFlag;
  static const CtxSet   MergeIdx;
#if JVET_AG0164_AFFINE_GPM
  static const CtxSet   GpmMergeIdx;
  static const CtxSet   GpmAffMergeIdx;
#endif
#if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
  static const CtxSet   TmMergeIdx;
#endif
#if JVET_X0049_ADAPT_DMVR
  static const CtxSet   BMMergeFlag;
#endif
#if JVET_AD0182_AFFINE_DMVR_PLUS_EXTENSIONS
  static const CtxSet   affBMFlag;
#endif
#if JVET_AA0070_RRIBC
  static const CtxSet   rribcFlipType;
#endif
#if JVET_AC0060_IBC_BVP_CLUSTER_RRIBC_BVD_SIGN_DERIV
  static const CtxSet bvOneZeroComp;
#endif
#if JVET_Y0065_GPM_INTRA
  static const CtxSet   GPMIntraFlag;
#endif
#if JVET_AI0082_GPM_WITH_INTER_IBC
  static const CtxSet   GpmInterIbcFlag;
  static const CtxSet   GpmInterIbcIdx;
#endif
  static const CtxSet   PredMode;
#if JVET_AI0136_ADAPTIVE_DUAL_TREE
  static const CtxSet   SeparateTree;
#endif
  static const CtxSet   MultiRefLineIdx;
  static const CtxSet   IntraLumaMpmFlag;
#if SECONDARY_MPM
  static const CtxSet   IntraLumaSecondMpmFlag;
#if JVET_AD0085_MPM_SORTING
  static const CtxSet   IntraLumaSecondMpmIdx;
#endif
#endif
  static const CtxSet   IntraLumaPlanarFlag;
#if SECONDARY_MPM
  static const CtxSet   IntraLumaMPMIdx;
#endif
  static const CtxSet   CclmModeFlag;
  static const CtxSet   CclmModeIdx;
  static const CtxSet   IntraChromaPredMode;
#if JVET_AD0188_CCP_MERGE
  static const CtxSet   nonLocalCCP;
#endif
#if JVET_AG0154_DECODER_DERIVED_CCP_FUSION
  static const CtxSet   decoderDerivedCCP;
  static const CtxSet   ddNonLocalCCP;
#endif
#if JVET_Z0050_DIMD_CHROMA_FUSION
#if ENABLE_DIMD
  static const CtxSet   DimdChromaMode;
#endif
  static const CtxSet   ChromaFusionMode;
#if JVET_AC0119_LM_CHROMA_FUSION
  static const CtxSet   ChromaFusionType;
  static const CtxSet   ChromaFusionCclm;
#endif
#endif
#if JVET_AC0071_DBV
  static const CtxSet DbvChromaMode;
#endif
  static const CtxSet   MipFlag;
#if JVET_V0130_INTRA_TMP
  static const CtxSet   TmpFlag;
#if JVET_AD0086_ENHANCED_INTRA_TMP
  static const CtxSet   TmpIdx;
  static const CtxSet   TmpFusion;
#if JVET_AG0136_INTRA_TMP_LIC
  static const CtxSet   TmpLic;
  static const CtxSet   ItmpLicIndex;
#endif
#endif  
#endif
#if MMLM
  static const CtxSet   MMLMFlag;
#endif
  static const CtxSet   DeltaQP;
  static const CtxSet   InterDir;
  static const CtxSet   RefPic;
#if JVET_Z0054_BLK_REF_PIC_REORDER
  static const CtxSet   RefPicLC;
#endif
  static const CtxSet   MmvdFlag;
  static const CtxSet   MmvdMergeIdx;
  static const CtxSet   MmvdStepMvpIdx;
#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
  static const CtxSet   MmvdStepMvpIdxECM3;
#endif
#if JVET_AG0112_REGRESSION_BASED_GPM_BLENDING
  static const CtxSet   GeoBlendFlag;
#if JVET_AJ0274_REGRESSION_GPM_TM
  static const CtxSet   GeoBlendTMFlag;
#endif
#endif
#if JVET_W0097_GPM_MMVD_TM
  static const CtxSet   GeoMmvdFlag;
  static const CtxSet   GeoMmvdStepMvpIdx;
#endif
#if JVET_AA0058_GPM_ADAPTIVE_BLENDING
  static const CtxSet   GeoBldFlag;
#endif
#if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
  static const CtxSet   GeoSubModeIdx;
#endif
  static const CtxSet   SubblockMergeFlag;
  static const CtxSet   AffineFlag;
  static const CtxSet   AffineType;
  static const CtxSet   AffMergeIdx;
#if AFFINE_MMVD
  static const CtxSet   AfMmvdFlag;
  static const CtxSet   AfMmvdIdx;
  static const CtxSet   AfMmvdOffsetStep;
#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
  static const CtxSet   AfMmvdOffsetStepECM3;
#endif
#endif
  #if JVET_AA0061_IBC_MBVD
  static const CtxSet   IbcMbvdFlag;
  static const CtxSet   IbcMbvdMergeIdx;
  static const CtxSet   IbcMbvdStepMvpIdx;
#endif
#if JVET_AC0112_IBC_CIIP
  static const CtxSet   IbcCiipFlag;
  static const CtxSet   IbcCiipIntraIdx;
#endif
#if JVET_AC0112_IBC_GPM
  static const CtxSet   IbcGpmFlag;
  static const CtxSet   IbcGpmIntraFlag;
  static const CtxSet   IbcGpmSplitDirSetFlag;
  static const CtxSet   IbcGpmBldIdx;
#endif
#if JVET_AC0112_IBC_LIC
  static const CtxSet   IbcLicFlag;
#if JVET_AE0078_IBC_LIC_EXTENSION
  static const CtxSet   IbcLicIndex;
#endif
#endif

#if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
  static const CtxSet   TMMergeFlag;
#endif
#if TM_MRG
#if JVET_X0141_CIIP_TIMD_TM
  static const CtxSet   CiipTMMergeFlag;
#endif
#endif
  static const CtxSet   Mvd;
#if JVET_Z0131_IBC_BVD_BINARIZATION
  static const CtxSet   Bvd;
#endif
#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED || JVET_AC0104_IBC_BVD_PREDICTION
  static const CtxSet   MvsdIdx;
#endif
#if JVET_AD0140_MVD_PREDICTION && JVET_AC0104_IBC_BVD_PREDICTION
  static const CtxSet   MvsdIdxIBC;
#endif

#if JVET_AD0140_MVD_PREDICTION
  static const CtxSet   MvsdIdxMVDMSB;
#endif

#if JVET_AC0104_IBC_BVD_PREDICTION
  static const CtxSet   MvsdIdxBVDMSB;
#endif

#if MULTI_HYP_PRED
  static const CtxSet   MultiHypothesisFlag;
  static const CtxSet   MHRefPic;
  static const CtxSet   MHWeight;
#endif
  static const CtxSet   BDPCMMode;
  static const CtxSet   QtRootCbf;
  static const CtxSet   ACTFlag;
  static const CtxSet   QtCbf           [3];    // [ channel ]
  static const CtxSet   SigCoeffGroup   [2];    // [ ChannelType ]
  static const CtxSet   LastX           [2];    // [ ChannelType ]
  static const CtxSet   LastY           [2];    // [ ChannelType ]
#if JVET_AE0102_LFNST_CTX
  static const CtxSet   SigFlagL[6];    // [ ChannelType + State ]
  static const CtxSet   ParFlagL[2];    // [ ChannelType ]
#if JVET_AG0100_TRANSFORM_COEFFICIENT_CODING
  static const CtxSet   GtxFlagL[8];    // [ ChannelType + x ]
#else
  static const CtxSet   GtxFlagL[4];    // [ ChannelType + x ]
#endif
#endif
  static const CtxSet   SigFlag         [6];    // [ ChannelType + State ]
  static const CtxSet   ParFlag         [2];    // [ ChannelType ]
#if JVET_AG0100_TRANSFORM_COEFFICIENT_CODING
  static const CtxSet   GtxFlag[8];    // [ ChannelType + x ]
#else
  static const CtxSet   GtxFlag         [4];    // [ ChannelType + x ]
#endif
  static const CtxSet   TsSigCoeffGroup;
  static const CtxSet   TsSigFlag;
  static const CtxSet   TsParFlag;
  static const CtxSet   TsGtxFlag;
  static const CtxSet   TsLrg1Flag;
  static const CtxSet   TsResidualSign;
#if JVET_AG0143_INTER_INTRA
  static const CtxSet   SigCoeffGroupCtxSetSwitch[2];   // [ ChannelType ]
  static const CtxSet   SigFlagCtxSetSwitch[6];         // [ ChannelType + State ]
  static const CtxSet   ParFlagCtxSetSwitch[2];         // [ ChannelType ]
#if JVET_AG0100_TRANSFORM_COEFFICIENT_CODING
  static const CtxSet   GtxFlagCtxSetSwitch[8];    // [ ChannelType + x ]
#else
  static const CtxSet   GtxFlagCtxSetSwitch[4];    // [ ChannelType + x ]
#endif
  static const CtxSet   LastXCtxSetSwitch[2];           // [ ChannelType ]
  static const CtxSet   LastYCtxSetSwitch[2];           // [ ChannelType ]
  static const CtxSet   TsSigCoeffGroupCtxSetSwitch;
  static const CtxSet   TsSigFlagCtxSetSwitch;
  static const CtxSet   TsParFlagCtxSetSwitch;
  static const CtxSet   TsGtxFlagCtxSetSwitch;
  static const CtxSet   TsLrg1FlagCtxSetSwitch;
  static const CtxSet   TsResidualSignCtxSetSwitch;
#endif
  static const CtxSet   MVPIdx;
#if JVET_X0083_BM_AMVP_MERGE_MODE
  static const CtxSet   amFlagState;
#endif
  static const CtxSet   SaoMergeFlag;
  static const CtxSet   SaoTypeIdx;
#if JVET_V0094_BILATERAL_FILTER
  static const CtxSet   BifCtrlFlags[];
#endif
#if JVET_AG0164_AFFINE_GPM
  static const CtxSet   AffineGPMFlag;
#endif
#if JVET_W0066_CCSAO
  static const CtxSet   CcSaoControlIdc;
#endif
  static const CtxSet   TransformSkipFlag;
  static const CtxSet   MTSIdx;
  static const CtxSet   LFNSTIdx;
#if JVET_AG0061_INTER_LFNST_NSPT
  static const CtxSet   InterLFNSTIdx;
#endif
#if JVET_AI0050_INTER_MTSS
  static const CtxSet   InterLFNSTIntraIdx;
#endif
  static const CtxSet   PLTFlag;
  static const CtxSet   RotationFlag;
  static const CtxSet   RunTypeFlag;
  static const CtxSet   IdxRunModel;
  static const CtxSet   CopyRunModel;
  static const CtxSet   SbtFlag;
  static const CtxSet   SbtQuadFlag;
  static const CtxSet   SbtHorFlag;
  static const CtxSet   SbtPosFlag;
  static const CtxSet   ChromaQpAdjFlag;
  static const CtxSet   ChromaQpAdjIdc;
  static const CtxSet   ImvFlag;
#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
  static const CtxSet   ImvFlagIBC;
#endif
#if ENABLE_DIMD
  static const CtxSet   DimdFlag;
#endif
#if JVET_AH0076_OBIC
  static const CtxSet   obicFlag;
#endif
#if JVET_W0123_TIMD_FUSION
  static const CtxSet   TimdFlag;
#if JVET_AJ0061_TIMD_MERGE
  static const CtxSet   TimdMrgFlag;
#endif
#endif
#if JVET_AB0155_SGPM
  static const CtxSet   SgpmFlag;
#endif
#if ENABLE_OBMC
  static const CtxSet   ObmcFlag;
#endif 
  static const CtxSet   BcwIdx;
  static const CtxSet   ctbAlfFlag;
  static const CtxSet   ctbAlfAlternative;
  static const CtxSet   AlfUseTemporalFilt;
  static const CtxSet   CcAlfFilterControlFlag;
  static const CtxSet   CiipFlag;
#if JVET_AG0135_AFFINE_CIIP
  static const CtxSet   CiipAffineFlag;
#endif
  static const CtxSet   SmvdFlag;
#if JVET_AG0098_AMVP_WITH_SBTMVP
  static const CtxSet   amvpSbTmvpFlag;
  static const CtxSet   amvpSbTmvpMvdIdx;
#endif
  static const CtxSet   IBCFlag;
#if JVET_AE0169_BIPREDICTIVE_IBC
  static const CtxSet   BiPredIbcFlag;
#endif
  static const CtxSet   ISPMode;
  static const CtxSet   JointCbCrFlag;
#if INTER_LIC
  static const CtxSet   LICFlag;
#if JVET_AG0276_LIC_SLOPE_ADJUST
  static const CtxSet   LicDelta;
#endif
#endif
#if SIGN_PREDICTION
  static const CtxSet   signPred[2];
#endif
#if JVET_Z0050_CCLM_SLOPE
  static const CtxSet   CclmDeltaFlags;
#endif
#if JVET_AA0126_GLM
  static const CtxSet   GlmFlags;
#endif
#if JVET_AA0057_CCCM
  static const CtxSet   CccmFlag;
#endif
#if JVET_AE0100_BVGCCCM
  static const CtxSet   BvgCccmFlag;
#endif
#if JVET_AD0202_CCCM_MDF
  static const CtxSet   CccmMpfFlag;
#endif
#if JVET_AD0120_LBCCP
  static const CtxSet   CcInsideFilterFlag;
#endif
#if JVET_AB0157_TMRL
  static const CtxSet   TmrlDerive;
#if JVET_AJ0081_CHROMA_TMRL
  static const CtxSet   ChromaTmrlFlag;
#endif
#endif
#if JVET_AE0059_INTER_CCCM
  static const CtxSet   InterCccmFlag;
#endif
#if JVET_AF0073_INTER_CCP_MERGE
  static const CtxSet   InterCcpMergeFlag;
#endif
#if JVET_AG0058_EIP
  static const CtxSet   EipFlag;
#endif
#if JVET_AG0059_CCP_MERGE_ENHANCEMENT
  static const CtxSet   CCPMergeFusionFlag;
  static const CtxSet   CCPMergeFusionType;
#endif
#if JVET_AH0066_JVET_AH0202_CCP_MERGE_LUMACBF0
  static const CtxSet   InterCcpMergeZeroRootCbfIdc;
#endif
  static const unsigned NumberOfContexts;

  // combined sets for less complex copying
  // NOTE: The contained CtxSet's should directly follow each other in the initalization list;
  //       otherwise, you will copy more elements than you want !!!
  static const CtxSet   Sao;
  static const CtxSet   Alf;
  static const CtxSet   Palette;
  static const CtxSet   Split;

public:
  static const std::vector<uint8_t>&  getInitTable( unsigned initId );
private:
  static std::vector<std::vector<uint8_t> > sm_InitTables;
  static CtxSet addCtxSet( std::initializer_list<std::initializer_list<uint8_t> > initSet2d);
};


class FracBitsAccess
{
public:
  virtual BinFracBits getFracBitsArray( unsigned ctxId ) const = 0;
};



template <class BinProbModel>
class CtxStore : public FracBitsAccess
{
public:
  CtxStore();
  CtxStore( bool dummy );
  CtxStore( const CtxStore<BinProbModel>& ctxStore );
public:
  void copyFrom(const CtxStore<BinProbModel>& src)
  {
    checkInit();
    std::copy_n(reinterpret_cast<const char*>(src.m_ctx), sizeof(BinProbModel) * ContextSetCfg::NumberOfContexts,
      reinterpret_cast<char*>(m_ctx));
  }
  void copyFrom(const CtxStore<BinProbModel>& src, const CtxSet& ctxSet)
  {
    checkInit();
    std::copy_n(reinterpret_cast<const char*>(src.m_ctx + ctxSet.Offset), sizeof(BinProbModel) * ctxSet.Size,
      reinterpret_cast<char*>(m_ctx + ctxSet.Offset));
  }
  void init(int qp, int initId);
#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  void loadWinSizes( const std::vector<uint8_t>&   windows );
  void saveWinSizes( std::vector<uint8_t>&         windows ) const;
  void loadWeights( const std::vector <uint8_t>&  weights );
  void saveWeights( std::vector<uint8_t>&         weights )  const;
  void loadPStates( const std::vector<std::pair<uint16_t, uint16_t>>&  probStates );
  void savePStates( std::vector<std::pair<uint16_t, uint16_t>>&        probStates )  const;
#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
  void loadRateOffsets( const std::vector<uint8_t>& rateOffsets0, const std::vector<uint8_t>& rateOffsets1 );
  void saveRateOffsets( std::vector<uint8_t>& rateOffsets0, std::vector<uint8_t>& rateOffsets1 ) const;
#endif
#else
  void loadPStates( const std::vector<uint16_t>&  probStates );
  void savePStates( std::vector<uint16_t>&        probStates )  const;
#endif

#if JVET_AG0117_CABAC_SPATIAL_TUNING
  void updateCtxs(BinStoreVector *binStoreElemVector)
  {
    BinStoreVector& vector = *binStoreElemVector;
    
    int numCtxTypes = int( vector.size() );
    
    for ( int ctxType = 0; ctxType < numCtxTypes; ctxType++ )
    {
      const BinStoreElem& store = vector[ ctxType ];

      for ( int i = 0; i < store.count; i++ )
      {
        m_ctxBuffer[ store.ctxId ].updateShortWin( store.bin(i) );
      }
    }
  }
#endif

  const BinProbModel& operator[]      ( unsigned  ctxId  )  const { return m_ctx[ctxId]; }
  BinProbModel&       operator[]      ( unsigned  ctxId  )        { return m_ctx[ctxId]; }
  uint32_t            estFracBits     ( unsigned  bin,
                                        unsigned  ctxId  )  const { return m_ctx[ctxId].estFracBits(bin); }

  BinFracBits         getFracBitsArray( unsigned  ctxId  )  const { return m_ctx[ctxId].getFracBitsArray(); }

private:
  inline void checkInit() { if( m_ctx ) return; m_ctxBuffer.resize( ContextSetCfg::NumberOfContexts ); m_ctx = m_ctxBuffer.data(); }
private:
  std::vector<BinProbModel> m_ctxBuffer;
  BinProbModel*             m_ctx;
};



class Ctx;
class SubCtx
{
  friend class Ctx;
public:
  SubCtx( const CtxSet& ctxSet, const Ctx& ctx ) : m_ctxSet( ctxSet          ), m_ctx( ctx          ) {}
  SubCtx( const SubCtx& subCtx )                 : m_ctxSet( subCtx.m_ctxSet ), m_ctx( subCtx.m_ctx ) {}
  const SubCtx& operator= ( const SubCtx& ) = delete;
private:
  const CtxSet  m_ctxSet;
  const Ctx&    m_ctx;
};



class Ctx : public ContextSetCfg
{
public:
  Ctx();
  Ctx( const BinProbModel_Std*    dummy );
  Ctx( const Ctx&                 ctx   );

public:
  const Ctx& operator= ( const Ctx& ctx )
  {
    m_BPMType = ctx.m_BPMType;
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std  .copyFrom( ctx.m_ctxStore_Std   );  break;
    default:        break;
    }
    ::memcpy( m_GRAdaptStats, ctx.m_GRAdaptStats, sizeof( unsigned ) * RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS );
    return *this;
  }

  SubCtx operator= ( SubCtx&& subCtx )
  {
    m_BPMType = subCtx.m_ctx.m_BPMType;
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std  .copyFrom( subCtx.m_ctx.m_ctxStore_Std,   subCtx.m_ctxSet );  break;
    default:        break;
    }
    return std::move(subCtx);
  }

  void  init(int qp, int initId)
  {
    switch (m_BPMType)
    {
    case BPM_Std:   m_ctxStore_Std  .init( qp, initId );  break;
    default:        break;
    }
    for (std::size_t k = 0; k < RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS; k++)
    {
      m_GRAdaptStats[k] = 0;
    }
  }

#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
  void  loadWeights( const std::vector< uint8_t>& weights )
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.loadWeights( weights );  break;
    default:        break;
    }
  }

  void  saveWeights( std::vector<uint8_t>& weights ) const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.saveWeights( weights );  break;
    default:        break;
    }
  }

  void  loadWinSizes( const std::vector<uint8_t>& windows )
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.loadWinSizes( windows );  break;
    default:        break;
    }
  }

  void  saveWinSizes( std::vector<uint8_t>& windows ) const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.saveWinSizes( windows );  break;
    default:        break;
    }
  }

  void  loadPStates( const std::vector<std::pair<uint16_t, uint16_t>>& probStates )
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.loadPStates( probStates );  break;
    default:        break;
    }
  }

  void  savePStates( std::vector<std::pair<uint16_t, uint16_t>>& probStates ) const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.savePStates( probStates );  break;
    default:        break;
    }
  }

#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
  void  loadRateOffsets( const std::vector<uint8_t>& rateOffsets0, const std::vector<uint8_t>& rateOffsets1 )
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.loadRateOffsets( rateOffsets0, rateOffsets1 );  break;
    default:        break;
    }
  }

  void  saveRateOffsets( std::vector<uint8_t>& rateOffsets0, std::vector<uint8_t>& rateOffsets1 ) const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std.saveRateOffsets( rateOffsets0, rateOffsets1 );  break;
    default:        break;
    }
}
#endif

#else
  void  loadPStates( const std::vector<uint16_t>& probStates )
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std  .loadPStates( probStates );  break;
    default:        break;
    }
  }

  void  savePStates( std::vector<uint16_t>& probStates ) const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   m_ctxStore_Std  .savePStates( probStates );  break;
    default:        break;
    }
  }
#endif

  void  initCtxAndWinSize( unsigned ctxId, const Ctx& ctx, const uint8_t winSize )
  {
    switch( m_BPMType )
    {
    case BPM_Std:
      m_ctxStore_Std  [ctxId] = ctx.m_ctxStore_Std  [ctxId];
      m_ctxStore_Std  [ctxId] . setLog2WindowSize   (winSize);
      break;
    default:
      break;
    }
  }

  const unsigned&     getGRAdaptStats ( unsigned      id )      const { return m_GRAdaptStats[id]; }
  unsigned&           getGRAdaptStats ( unsigned      id )            { return m_GRAdaptStats[id]; }

public:
  unsigned            getBPMType      ()                        const { return m_BPMType; }
  const Ctx&          getCtx          ()                        const { return *this; }
  Ctx&                getCtx          ()                              { return *this; }

  explicit operator   const CtxStore<BinProbModel_Std>  &()     const { return m_ctxStore_Std; }
  explicit operator         CtxStore<BinProbModel_Std>  &()           { return m_ctxStore_Std; }

  const FracBitsAccess&   getFracBitsAcess()  const
  {
    switch( m_BPMType )
    {
    case BPM_Std:   return m_ctxStore_Std;
    default:        THROW("BPMType out of range");
    }
  }
#if JVET_AG0196_CABAC_RETRAIN
  // direct access to a model prm
  int getRate(int ctxidx) const
  {
    return m_ctxStore_Std[ctxidx].getWinSizes();
  }
#endif
private:
  BPMType                       m_BPMType;
  CtxStore<BinProbModel_Std>    m_ctxStore_Std;
protected:
  unsigned                      m_GRAdaptStats[RExt__GOLOMB_RICE_ADAPTATION_STATISTICS_SETS];
#if ENABLE_SPLIT_PARALLELISM

public:
  int64_t cacheId;
  bool    cacheUsed;
#endif
};



typedef dynamic_cache<Ctx> CtxCache;

class TempCtx
{
  TempCtx( const TempCtx& ) = delete;
  const TempCtx& operator=( const TempCtx& ) = delete;
public:
  TempCtx ( CtxCache* cache )                     : m_ctx( *cache->get() ), m_cache( cache ) {}
  TempCtx ( CtxCache* cache, const Ctx& ctx    )  : m_ctx( *cache->get() ), m_cache( cache ) { m_ctx = ctx; }
  TempCtx ( CtxCache* cache, SubCtx&&   subCtx )  : m_ctx( *cache->get() ), m_cache( cache ) { m_ctx = std::forward<SubCtx>(subCtx); }
  ~TempCtx()                                      { m_cache->cache( &m_ctx ); }
  void operator=( const Ctx& ctx )          { m_ctx = ctx ; }
  void operator=( SubCtx&&   subCtx )       { m_ctx = std::forward<SubCtx>( subCtx ); }
  operator const Ctx& ()           const          { return m_ctx; }
  operator       Ctx& ()                          { return m_ctx; }
private:
  Ctx&      m_ctx;
  CtxCache* m_cache;
};

#if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
class CtxStateBuf
{
public:
  CtxStateBuf() : m_valid( false ) {}
  ~CtxStateBuf() {}
  inline void reset() { m_valid = false; }
  inline bool getIfValid( Ctx &ctx ) const
  {
    if( m_valid )
    {
      ctx.loadPStates( m_states );
      ctx.loadWeights( m_weights );
      ctx.loadWinSizes( m_rate );
#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
      ctx.loadRateOffsets( m_rateOffset[0], m_rateOffset[1] );
#endif
      return true;
    }
    return false;
  }
  inline void store( const Ctx &ctx )
  {
    ctx.savePStates( m_states );
    ctx.saveWeights( m_weights );
    ctx.saveWinSizes( m_rate );
#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
    ctx.saveRateOffsets( m_rateOffset[0], m_rateOffset[1] );
#endif
    m_valid = true;
  }

private:
  std::vector<std::pair<uint16_t, uint16_t>> m_states;
  bool                 m_valid;
  std::vector<uint8_t> m_weights;
  std::vector<uint8_t> m_rate;
#if JVET_AG0196_WINDOWS_OFFSETS_SLICETYPE
  std::vector<uint8_t> m_rateOffset[2];
#endif
};

class CtxStateArray
{
public:
  CtxStateArray() {}
  ~CtxStateArray() {}

  inline void resetAll()
  {
    for( std::size_t k = 0; k < m_data.size(); k++ )
    {
      m_data[k].reset();
    }
  }

  inline void resize( std::size_t reqSize )
  {
    if( m_data.size() < reqSize )
    {
      m_data.resize( reqSize );
    }
  }

  inline bool getIfValid( Ctx &ctx ) const
  {
    if( m_data.size() )
    {
      return m_data[0].getIfValid( ctx );
    }
    return false;
  }

#if JVET_AG0196_CABAC_RETRAIN
  inline void store( const Ctx &ctx, const SliceType sliceType )
#else
  inline void store( const Ctx &ctx )
#endif
  {
    if( !m_data.size() )
    {
      resize( 1 );
    }
    m_data[0].store( ctx );

#if JVET_AG0196_CABAC_RETRAIN
    m_sliceType = sliceType;
#endif
  }

  inline size_t size() const
  {    
    return  m_data.size();
  }

#if JVET_AG0196_CABAC_RETRAIN
  SliceType getSliceType() const { return m_sliceType; }
#endif

private:
  std::vector<CtxStateBuf> m_data;
#if JVET_AG0196_CABAC_RETRAIN
  SliceType m_sliceType;
#endif
};

class CtxStateStore
{
public:
  CtxStateStore() { static_assert((B_SLICE < NUMBER_OF_SLICE_TYPES - 1) && (P_SLICE < NUMBER_OF_SLICE_TYPES - 1), "index out of bound"); }
  ~CtxStateStore() {}

  void storeCtx( const Slice* slice, const Ctx& ctx )
  {
#if JVET_AH0176_LOW_DELAY_B_CTX
    SliceType s = slice->getSliceType();

    if (s != I_SLICE)
    {
      int t = (s == P_SLICE ? 1 : 0);
#else
    SliceType t = slice->getSliceType();

    if( t != I_SLICE )
    {
#endif
      CtxStateArray* ctxStateArray = nullptr;
      std::pair<int, int> entry( slice->getTLayer(), slice->getSliceQp() );

      if( m_stateBuf[t].find( entry ) != m_stateBuf[t].end() || m_stateBuf[t].size() < TEMP_CABAC_BUFFER_SIZE )
      {
        ctxStateArray = &m_stateBuf[t][entry];
      }
      else
      {
        if( m_stateBuf[t].size() == TEMP_CABAC_BUFFER_SIZE )
        {         
          m_stateBuf[t].erase( m_stateBuf[t].begin() );
        }

        ctxStateArray = &m_stateBuf[t][entry];

        CHECK( m_stateBuf[t].size() > TEMP_CABAC_BUFFER_SIZE, "Wrong buffer size" );
      }

#if JVET_AG0196_CABAC_RETRAIN
      ctxStateArray->store( ctx, slice->getCabacInitSliceType() );
#else
      ctxStateArray->store( ctx );
#endif
    }
  }

#if JVET_AG0196_CABAC_RETRAIN
  bool loadCtx( Slice* slice, Ctx& ctx )
#else
  bool loadCtx( const Slice* slice, Ctx& ctx )
#endif
  {
#if JVET_AH0176_LOW_DELAY_B_CTX
    SliceType s = slice->getSliceType();

    if (s != I_SLICE)
    {
      int t = (s == P_SLICE ? 1 : 0);
#else
    SliceType t = slice->getSliceType();

    if( t != I_SLICE )
    {
#endif
      std::pair<int, int> entry( slice->getTLayer(), slice->getSliceQp() );

      if( m_stateBuf[t].find( entry ) != m_stateBuf[t].end() )
      {
        const CtxStateArray& ctxStateArray = m_stateBuf[t][entry];
#if JVET_AG0196_CABAC_RETRAIN
        slice->setCabacInitSliceType( m_stateBuf[t][entry].getSliceType() );
#endif
        return ctxStateArray.getIfValid( ctx );
      }      
    }
    return false;
  }

  void clearValid()
  {
    m_stateBuf[0].clear();
    m_stateBuf[1].clear();
  }

private:
  std::map<std::pair<int, int>, CtxStateArray> m_stateBuf[2];
};

class CABACDataStore
{
public:

#if JVET_AG0196_CABAC_RETRAIN
  bool loadCtxStates( Slice* slice, Ctx& ctx ) { return m_ctxStateStore.loadCtx( slice, ctx ); }
#else
  bool loadCtxStates( const Slice* slice, Ctx& ctx ) { return m_ctxStateStore.loadCtx( slice, ctx ); }
#endif
  void storeCtxStates( const Slice* slice, const Ctx& ctx ) { m_ctxStateStore.storeCtx( slice, ctx ); }

  void updateBufferState( const Slice* slice )
  {
#if JVET_Z0118_GDR && JVET_AD0206_CABAC_INIT_AT_GDR
    if( slice->getPendingRasInit() || slice->isInterGDR() )
#else
    if( slice->getPendingRasInit() )
#endif
    {
      m_ctxStateStore.clearValid();
    }
  }
private:
  CtxStateStore       m_ctxStateStore;
};
#endif

#endif