{-|
Module      : Nauty.Encoding.Internal
Description : Internal functions for encoding.
Copyright   : (c) Marcelo Garlet Milani, 2026
License     : MIT
Maintainer  : mgmilani@pm.me
Stability   : unstable

This module contains internal functions used by other modules.
Except for test cases, you should not import this module.
-}

module Nauty.Internal.Encoding where

import qualified Data.Text.Lazy as T
import Data.Bits
import Data.Word

-- | Encode an 8-bit vector as 6-bit words.
encodeVector :: Word64 -> [Word8] -> Word8 -> Int -> [Word8]
encodeVector :: Word64 -> [Word8] -> Word8 -> Int -> [Word8]
encodeVector Word64
lastValidBits [Word8]
bs Word8
acc Int
0 = Word8
acc Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: Word64 -> [Word8] -> Word8 -> Int -> [Word8]
encodeVector Word64
lastValidBits [Word8]
bs Word8
0 Int
6
encodeVector Word64
lastValidBits [Word8
b] Word8
acc Int
s
  | (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
lastValidBits) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
s = 
      (Word8
acc Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftR Word8
b (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
s))
      Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: [Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftR (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftL Word8
b Int
s) Int
2]
  | Bool
otherwise = [Word8
acc Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftR Word8
b (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
s)]
encodeVector Word64
lastValidBits (Word8
b:[Word8]
bs) Word8
acc Int
r = 
  (Word8
acc Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftR Word8
b (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
r)))
  Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: Word64 -> [Word8] -> Word8 -> Int -> [Word8]
encodeVector Word64
lastValidBits [Word8]
bs (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftR (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftL Word8
b Int
r) Int
2) ((Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2))
encodeVector Word64
_ [] Word8
_ Int
_ = []

-- | Minimum amount of bits required to represent the number.
numBits :: (Num a) => Word64 -> a
numBits :: forall a. Num a => Word64 -> a
numBits Word64
n = Word64 -> a
forall {t} {a}. (Num t, Num a, Bits t) => t -> a
numBits' (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
shiftR Word64
n Int
1)
  where
    numBits' :: t -> a
numBits' t
0 = a
1
    numBits' t
n' = a
1 a -> a -> a
forall a. Num a => a -> a -> a
+ t -> a
numBits' (t -> Int -> t
forall a. Bits a => a -> Int -> a
shiftR t
n' Int
1)

-- | Encode a number.
encodeNumber :: Word64 -> T.Text
encodeNumber :: Word64 -> Text
encodeNumber Word64
n 
  | Word64
n Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
63 = String -> Text
T.pack [Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$ Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
63]
  | Bool
otherwise = 
    let bits :: Int
bits = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ (Int
18 :: Int) Int -> Int -> Int
forall a. Num a => a -> a -> a
* (((Word64 -> Int
forall a. Num a => Word64 -> a
numBits Word64
n) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
7) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
18) :: Int
        encode' :: Int -> [Word8]
        encode' :: Int -> [Word8]
encode' Int
0 = [Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n]
        encode' Int
s = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
shiftR Word64
n Int
s Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
63) Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: Int -> [Word8]
encode' (Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
6)
    in  String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ (Word8 -> Char) -> [Word8] -> String
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> (Word8 -> Int) -> Word8 -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> (Word8 -> Word8) -> Word8 -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+Word8
63)) 
        ([Word8] -> String) -> [Word8] -> String
forall a b. (a -> b) -> a -> b
$ (Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take (Int
bits Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
18) ([Word8] -> [Word8]) -> [Word8] -> [Word8]
forall a b. (a -> b) -> a -> b
$ Word8 -> [Word8]
forall a. a -> [a]
repeat Word8
63)
        [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ Int -> [Word8]
encode' (Int
bits Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
6)