content: {-# LANGUAGE TypeFamilies #-}
  
  -- | Opinionated zero-based \(n\)-dimensional index and their bounds.
  module AtCoder.Extra.Ix0 where
  
  -- | Zero-based \(n\)-dimensional bounds: \([0, d_0) \times [0, d_1) \times \cdots \times [0, d_{n - 1})\).
  type Bounds0 i = i
  
  -- | Zero-based \(n\)-dimensional index.
  class Ix0 i where
    -- | Returns the size of the bounds: \(\prod_i d_i\).
    rangeSize0 :: Bounds0 i -> Int
  
    -- | Returns zero-based one-dimensional index, __without__ running boundary check.
    index0 :: Bounds0 i -> i -> Int
  
    -- | Returns whether an index is contained in bounds.
    inRange0 :: Bounds0 i -> i -> Bool
  
  instance Ix0 Int where
    {-# INLINE rangeSize0 #-}
    rangeSize0 d1 = d1
    {-# INLINE index0 #-}
    index0 _ x1 = x1
    {-# INLINE inRange0 #-}
    inRange0 d1 x1 = 0 <= x1 && x1 < d1
  
  instance Ix0 (Int, Int) where
    {-# INLINE rangeSize0 #-}
    rangeSize0 (!d2, !d1) = d2 * d1
    {-# INLINE index0 #-}
    index0 (!_, !d1) (!x2, !x1) = x2 * d1 + x1
    {-# INLINE inRange0 #-}
    inRange0 (!d2, !d1) (!x2, !x1) = 0 <= x2 && x2 < d2 && 0 <= x1 && x1 < d1
  
  instance Ix0 (Int, Int, Int) where
    {-# INLINE rangeSize0 #-}
    rangeSize0 (!d3, !d2, !d1) = d3 * d2 * d1
    {-# INLINE index0 #-}
    index0 (!_, !d2, !d1) (!x3, !x2, !x1) = (x3 * d2 + x2) * d1 + x1
    {-# INLINE inRange0 #-}
    inRange0 (!d3, !d2, !d1) (!x3, !x2, !x1) = 0 <= x3 && x3 < d3 && 0 <= x2 && x2 < d2 && 0 <= x1 && x1 < d1
  
  instance Ix0 (Int, Int, Int, Int) where
    {-# INLINE rangeSize0 #-}
    rangeSize0 (!d4, !d3, !d2, !d1) = d4 * d3 * d2 * d1
    {-# INLINE index0 #-}
    index0 (!_, !d3, !d2, !d1) (!x4, !x3, !x2, !x1) = ((x4 * d3 + x3) * d2 + x2) * d1 + x1
    {-# INLINE inRange0 #-}
    inRange0 (!d4, !d3, !d2, !d1) (!x4, !x3, !x2, !x1) = 0 <= x4 && x4 < d4 && 0 <= x3 && x3 < d3 && 0 <= x2 && x2 < d2 && 0 <= x1 && x1 < d1
  
  instance Ix0 (Int, Int, Int, Int, Int) where
    {-# INLINE rangeSize0 #-}
    rangeSize0 (!d5, !d4, !d3, !d2, !d1) = d5 * d4 * d3 * d2 * d1
    {-# INLINE index0 #-}
    index0 (!_, !d4, !d3, !d2, !d1) (!x5, !x4, !x3, !x2, !x1) = (((x5 * d4 + x4) * d3 + x3) * d2 + x2) * d1 + x1
    {-# INLINE inRange0 #-}
    inRange0 (!d5, !d4, !d3, !d2, !d1) (!x5, !x4, !x3, !x2, !x1) = 0 <= x5 && x5 < d5 && 0 <= x4 && x4 < d4 && 0 <= x3 && x3 < d3 && 0 <= x2 && x2 < d2 && 0 <= x1 && x1 < d1
  
  instance Ix0 (Int, Int, Int, Int, Int, Int) where
    {-# INLINE rangeSize0 #-}
    rangeSize0 (!d6, !d5, !d4, !d3, !d2, !d1) = d6 * d5 * d4 * d3 * d2 * d1
    {-# INLINE index0 #-}
    index0 (!_, !d5, !d4, !d3, !d2, !d1) (!x6, !x5, !x4, !x3, !x2, !x1) = ((((x6 * d5 + x5) * d4 + x4) * d3 + x3) * d2 + x2) * d1 + x1
    {-# INLINE inRange0 #-}
    inRange0 (!d6, !d5, !d4, !d3, !d2, !d1) (!x6, !x5, !x4, !x3, !x2, !x1) = 0 <= x6 && x6 < d6 && 0 <= x5 && x5 < d5 && 0 <= x4 && x4 < d4 && 0 <= x3 && x3 < d3 && 0 <= x2 && x2 < d2 && 0 <= x1 && x1 < d1
  