{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE FlexibleContexts #-}
{-#LANGUAGE TypeOperators #-}
{-#LANGUAGE ScopedTypeVariables #-}
{-#LANGUAGE UndecidableInstances #-}
module Foreign.Storable.Generic.Tools (
Size,
Alignment,
Offset,
Filling(..),
calcOffsets,
calcSize,
calcAlignment,
getFilling
) where
import Data.List
data Filling = Size Int | Padding Int deriving(Show, Eq)
not_zero :: Filling -> Bool
not_zero (Size 0) = False
not_zero (Padding 0) = False
not_zero _ = True
type Size = Int
type Alignment = Int
type Offset = Int
getFilling :: [(Size,Alignment)]
-> [Filling]
getFilling size_align = reverse $ filter not_zero $ getFilling' (ordered ++ [(gl_size,0)]) 0 0 []
where offsets = calcOffsets size_align :: [Offset]
sizes = map fst size_align :: [Size]
ordered = sortBy (\(o1,_) (o2,_) -> compare o1 o2) $
zip offsets sizes :: [(Offset,Size)]
gl_size = calcSize size_align :: Offset
getFilling' :: [(Offset, Size)]
-> Size
-> Offset
-> [Filling]
-> [Filling]
getFilling' [] _ _ acc = acc
getFilling' ((o2,s2):rest) s1 o1 acc = getFilling' rest s2 o2 (Size s2 : Padding ((o2-o1) - s1) : acc )
{-# NOINLINE calcOffsets #-}
calcOffsets :: [(Size, Alignment)]
-> [Offset]
calcOffsets [] = []
calcOffsets size_align = reverse $ fst $ calcOffsets' size_align 0 []
{-# NOINLINE calcOffsets' #-}
calcOffsets' :: [(Size, Alignment)]
-> Int
-> [Offset]
-> ([Offset], Int)
calcOffsets' [] inter acc = (acc, inter)
calcOffsets' ((s,a):rest) inter acc = calcOffsets' rest (last_off + s) (last_off: acc)
where p = (a - inter) `mod` a
last_off = inter + p :: Offset
{-# NOINLINE calcSize #-}
calcSize :: [(Size, Alignment)]
-> Size
calcSize size_align = inter + ((glob_align - inter) `mod` glob_align)
where glob_align = calcAlignment $ map snd size_align
inter = snd $ calcOffsets' size_align 0 []
{-# NOINLINE calcAlignment #-}
calcAlignment :: [Alignment]
-> Alignment
calcAlignment aligns = calcAlignment' aligns 1
calcAlignment' :: [Alignment]
-> Alignment
-> Alignment
calcAlignment' [] glob = glob
calcAlignment' (al:aligns) glob = calcAlignment' aligns (max glob al)