{-# LANGUAGE Safe #-}
module Data.BinPacking (BinPacker,
BinPackerError(..),
packByOrder,
packLargeFirst
)
where
import Data.List (sortOn)
data (Num size, Ord size, Show size, Show obj) => BinPackerError size obj =
BPTooFewBins [(size, obj)]
| BPSizeTooLarge size (size, obj)
| BPOther String
deriving (BinPackerError size obj -> BinPackerError size obj -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall size obj.
(Num size, Ord size, Show size, Show obj, Eq obj) =>
BinPackerError size obj -> BinPackerError size obj -> Bool
/= :: BinPackerError size obj -> BinPackerError size obj -> Bool
$c/= :: forall size obj.
(Num size, Ord size, Show size, Show obj, Eq obj) =>
BinPackerError size obj -> BinPackerError size obj -> Bool
== :: BinPackerError size obj -> BinPackerError size obj -> Bool
$c== :: forall size obj.
(Num size, Ord size, Show size, Show obj, Eq obj) =>
BinPackerError size obj -> BinPackerError size obj -> Bool
Eq, ReadPrec [BinPackerError size obj]
ReadPrec (BinPackerError size obj)
ReadS [BinPackerError size obj]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadPrec [BinPackerError size obj]
forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadPrec (BinPackerError size obj)
forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
Int -> ReadS (BinPackerError size obj)
forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadS [BinPackerError size obj]
readListPrec :: ReadPrec [BinPackerError size obj]
$creadListPrec :: forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadPrec [BinPackerError size obj]
readPrec :: ReadPrec (BinPackerError size obj)
$creadPrec :: forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadPrec (BinPackerError size obj)
readList :: ReadS [BinPackerError size obj]
$creadList :: forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
ReadS [BinPackerError size obj]
readsPrec :: Int -> ReadS (BinPackerError size obj)
$creadsPrec :: forall size obj.
(Num size, Ord size, Show size, Show obj, Read size, Read obj) =>
Int -> ReadS (BinPackerError size obj)
Read)
instance (Num size, Ord size, Show size, Show obj) => Show (BinPackerError size obj) where
show :: BinPackerError size obj -> String
show (BPTooFewBins [(size, obj)]
_) = String
"Too few bins"
show (BPSizeTooLarge size
binsize (size
objsize, obj
obj)) =
String
"Size " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show size
objsize forall a. [a] -> [a] -> [a]
++ String
" greater than bin size " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show size
binsize
forall a. [a] -> [a] -> [a]
++ String
" at " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show obj
obj
show (BPOther String
x) = String
x
type BinPacker = forall size obj. (Num size, Ord size, Show size, Show obj) =>
[size]
-> [(size, obj)]
-> Either (BinPackerError size obj) [[(size, obj)]]
packByOrder :: BinPacker
packByOrder :: BinPacker
packByOrder [size]
_ [] = forall a b. b -> Either a b
Right []
packByOrder [] [(size, obj)]
remainder = forall a b. a -> Either a b
Left (forall size obj. [(size, obj)] -> BinPackerError size obj
BPTooFewBins [(size, obj)]
remainder)
packByOrder (size
thisbinsize:[size]
otherbins) [(size, obj)]
sizes =
let fillBin :: size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin size
_ [] = forall a b. b -> Either a b
Right []
fillBin size
accumsize ((size
s, b
o):[(size, b)]
xs)
| size
s forall a. Ord a => a -> a -> Bool
> size
thisbinsize = forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall size obj. size -> (size, obj) -> BinPackerError size obj
BPSizeTooLarge size
thisbinsize (size
s, b
o)
| size
s forall a. Num a => a -> a -> a
+ size
accumsize forall a. Ord a => a -> a -> Bool
> size
thisbinsize = forall a b. b -> Either a b
Right []
| Bool
otherwise = do [(size, b)]
next <- size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin (size
accumsize forall a. Num a => a -> a -> a
+ size
s) [(size, b)]
xs
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (size
s, b
o) forall a. a -> [a] -> [a]
: [(size, b)]
next
in do [(size, obj)]
thisset <- forall {b}.
Show b =>
size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin size
0 [(size, obj)]
sizes
[[(size, obj)]]
next <- BinPacker
packByOrder [size]
otherbins (forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length [(size, obj)]
thisset) [(size, obj)]
sizes)
forall (m :: * -> *) a. Monad m => a -> m a
return ([(size, obj)]
thisset forall a. a -> [a] -> [a]
: [[(size, obj)]]
next)
packLargeFirst :: BinPacker
packLargeFirst :: BinPacker
packLargeFirst [size]
bins [(size, obj)]
sizes = BinPacker
packLargeFirst' [size]
bins (forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn forall a b. (a, b) -> a
fst [(size, obj)]
sizes)
packLargeFirst' :: BinPacker
packLargeFirst' :: BinPacker
packLargeFirst' [size]
_ [] = forall a b. b -> Either a b
Right []
packLargeFirst' [] [(size, obj)]
remainder = forall a b. a -> Either a b
Left (forall size obj. [(size, obj)] -> BinPackerError size obj
BPTooFewBins [(size, obj)]
remainder)
packLargeFirst' (size
thisbinsize:[size]
otherbins) [(size, obj)]
sizes =
let fillBin :: size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin size
_ [] = forall a b. b -> Either a b
Right []
fillBin size
accumsize [(size, b)]
sizelist =
case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (\(size, b)
x -> (forall a b. (a, b) -> a
fst (size, b)
x) forall a. Num a => a -> a -> a
+ size
accumsize forall a. Ord a => a -> a -> Bool
<= size
thisbinsize) [(size, b)]
sizelist of
([(size, b)]
_, []) ->
if size
accumsize forall a. Eq a => a -> a -> Bool
== size
0
then forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall size obj. size -> (size, obj) -> BinPackerError size obj
BPSizeTooLarge size
thisbinsize (forall a. [a] -> a
head [(size, b)]
sizelist)
else forall a b. b -> Either a b
Right []
([(size, b)]
nonmatches, ((size
s, b
o):[(size, b)]
matchxs)) ->
do [(size, b)]
next <- size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin (size
accumsize forall a. Num a => a -> a -> a
+ size
s) ([(size, b)]
nonmatches forall a. [a] -> [a] -> [a]
++ [(size, b)]
matchxs)
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (size
s, b
o) forall a. a -> [a] -> [a]
: [(size, b)]
next
in do [(size, obj)]
thisset <- forall {b}.
Show b =>
size -> [(size, b)] -> Either (BinPackerError size b) [(size, b)]
fillBin size
0 [(size, obj)]
sizes
[[(size, obj)]]
next <- BinPacker
packLargeFirst' [size]
otherbins (forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length [(size, obj)]
thisset) [(size, obj)]
sizes)
forall (m :: * -> *) a. Monad m => a -> m a
return ([(size, obj)]
thisset forall a. a -> [a] -> [a]
: [[(size, obj)]]
next)