{-#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(Int -> Filling -> ShowS
[Filling] -> ShowS
Filling -> String
(Int -> Filling -> ShowS)
-> (Filling -> String) -> ([Filling] -> ShowS) -> Show Filling
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Filling] -> ShowS
$cshowList :: [Filling] -> ShowS
show :: Filling -> String
$cshow :: Filling -> String
showsPrec :: Int -> Filling -> ShowS
$cshowsPrec :: Int -> Filling -> ShowS
Show, Filling -> Filling -> Bool
(Filling -> Filling -> Bool)
-> (Filling -> Filling -> Bool) -> Eq Filling
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Filling -> Filling -> Bool
$c/= :: Filling -> Filling -> Bool
== :: Filling -> Filling -> Bool
$c== :: Filling -> Filling -> Bool
Eq)
not_zero :: Filling -> Bool
not_zero :: Filling -> Bool
not_zero (Size    Int
0) = Bool
False
not_zero (Padding Int
0) = Bool
False
not_zero Filling
_           = Bool
True
type Size      = Int
type Alignment = Int
type Offset    = Int
getFilling :: [(Size,Alignment)] 
           -> [Filling]          
getFilling :: [(Int, Int)] -> [Filling]
getFilling [(Int, Int)]
size_align = [Filling] -> [Filling]
forall a. [a] -> [a]
reverse ([Filling] -> [Filling]) -> [Filling] -> [Filling]
forall a b. (a -> b) -> a -> b
$ (Filling -> Bool) -> [Filling] -> [Filling]
forall a. (a -> Bool) -> [a] -> [a]
filter Filling -> Bool
not_zero ([Filling] -> [Filling]) -> [Filling] -> [Filling]
forall a b. (a -> b) -> a -> b
$ [(Int, Int)] -> Int -> Int -> [Filling] -> [Filling]
getFilling' ([(Int, Int)]
ordered [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
forall a. [a] -> [a] -> [a]
++ [(Int
gl_size,Int
0)]) Int
0 Int
0 []
    where offsets :: [Int]
offsets = [(Int, Int)] -> [Int]
calcOffsets [(Int, Int)]
size_align  :: [Offset]
          sizes :: [Int]
sizes   = ((Int, Int) -> Int) -> [(Int, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Int) -> Int
forall a b. (a, b) -> a
fst [(Int, Int)]
size_align      :: [Size]
          ordered :: [(Int, Int)]
ordered = ((Int, Int) -> (Int, Int) -> Ordering)
-> [(Int, Int)] -> [(Int, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (\(Int
o1,Int
_) (Int
o2,Int
_) -> Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
o1 Int
o2) ([(Int, Int)] -> [(Int, Int)]) -> [(Int, Int)] -> [(Int, Int)]
forall a b. (a -> b) -> a -> b
$ 
                        [Int] -> [Int] -> [(Int, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int]
offsets [Int]
sizes   :: [(Offset,Size)] 
          gl_size :: Int
gl_size  = [(Int, Int)] -> Int
calcSize [(Int, Int)]
size_align    :: Offset   
getFilling' :: [(Offset, Size)] 
            -> Size             
            -> Offset           
            -> [Filling]        
            -> [Filling]        
getFilling' :: [(Int, Int)] -> Int -> Int -> [Filling] -> [Filling]
getFilling' []           Int
_ Int
_ [Filling]
acc = [Filling]
acc
getFilling' ((Int
o2,Int
s2):[(Int, Int)]
rest) Int
s1 Int
o1 [Filling]
acc = [(Int, Int)] -> Int -> Int -> [Filling] -> [Filling]
getFilling' [(Int, Int)]
rest Int
s2 Int
o2 (Int -> Filling
Size Int
s2 Filling -> [Filling] -> [Filling]
forall a. a -> [a] -> [a]
: Int -> Filling
Padding ((Int
o2Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
o1) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
s1) Filling -> [Filling] -> [Filling]
forall a. a -> [a] -> [a]
: [Filling]
acc )
{-# NOINLINE calcOffsets #-}
calcOffsets :: [(Size, Alignment)]  
            -> [Offset]             
calcOffsets :: [(Int, Int)] -> [Int]
calcOffsets []         = []
calcOffsets [(Int, Int)]
size_align = [Int] -> [Int]
forall a. [a] -> [a]
reverse ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ ([Int], Int) -> [Int]
forall a b. (a, b) -> a
fst (([Int], Int) -> [Int]) -> ([Int], Int) -> [Int]
forall a b. (a -> b) -> a -> b
$ [(Int, Int)] -> Int -> [Int] -> ([Int], Int)
calcOffsets' [(Int, Int)]
size_align Int
0 []
{-# NOINLINE calcOffsets' #-}
calcOffsets' :: [(Size, Alignment)] 
             -> Int                 
             -> [Offset]            
             -> ([Offset], Int)     
calcOffsets' :: [(Int, Int)] -> Int -> [Int] -> ([Int], Int)
calcOffsets' []           Int
inter [Int]
acc = ([Int]
acc, Int
inter)  
calcOffsets' ((Int
s,Int
a):[(Int, Int)]
rest) Int
inter [Int]
acc = [(Int, Int)] -> Int -> [Int] -> ([Int], Int)
calcOffsets' [(Int, Int)]
rest (Int
last_off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
s) (Int
last_offInt -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc)
    where p :: Int
p = (Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
inter) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
a 
          last_off :: Int
last_off = Int
inter Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
p    :: Offset
{-# NOINLINE calcSize #-}
calcSize :: [(Size, Alignment)] 
         -> Size                
calcSize :: [(Int, Int)] -> Int
calcSize [(Int, Int)]
size_align = Int
inter Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
glob_align Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
inter) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
glob_align)
    where glob_align :: Int
glob_align = [Int] -> Int
calcAlignment ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ((Int, Int) -> Int) -> [(Int, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Int) -> Int
forall a b. (a, b) -> b
snd [(Int, Int)]
size_align
          inter :: Int
inter      = ([Int], Int) -> Int
forall a b. (a, b) -> b
snd (([Int], Int) -> Int) -> ([Int], Int) -> Int
forall a b. (a -> b) -> a -> b
$ [(Int, Int)] -> Int -> [Int] -> ([Int], Int)
calcOffsets' [(Int, Int)]
size_align Int
0 []
{-# NOINLINE calcAlignment #-}
calcAlignment :: [Alignment] 
              -> Alignment   
calcAlignment :: [Int] -> Int
calcAlignment [Int]
aligns = [Int] -> Int -> Int
calcAlignment' [Int]
aligns Int
1
calcAlignment' :: [Alignment] 
               -> Alignment   
               -> Alignment   
calcAlignment' :: [Int] -> Int -> Int
calcAlignment' []          Int
glob = Int
glob
calcAlignment' (Int
al:[Int]
aligns) Int
glob = [Int] -> Int -> Int
calcAlignment' [Int]
aligns (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
glob Int
al)