apecs 0.2.0.0 → 0.2.0.1
raw patch · 6 files changed
+60/−13 lines, 6 files
Files
- apecs.cabal +1/−1
- src/Apecs/Slice.hs +11/−0
- src/Apecs/Stores.hs +17/−5
- src/Apecs/System.hs +10/−0
- src/Apecs/Types.hs +13/−6
- src/Apecs/Util.hs +8/−1
apecs.cabal view
@@ -1,5 +1,5 @@ name: apecs-version: 0.2.0.0+version: 0.2.0.1 homepage: https://github.com/jonascarpay/apecs#readme license: BSD3 license-file: LICENSE
src/Apecs/Slice.hs view
@@ -9,6 +9,7 @@ import Apecs.Types +-- | Slice version of foldM_ {-# INLINE sliceFoldM_ #-} sliceFoldM_ :: (a -> Entity c -> System w a) -> a -> Slice b -> System w () sliceFoldM_ f seed (Slice sl) = U.foldM'_ ((.Entity) . f) seed sl@@ -33,18 +34,23 @@ sliceFilterM :: (Entity c -> System w Bool) -> Slice c -> System w (Slice c) sliceFilterM fm (Slice vec) = Slice <$> U.filterM (fm . Entity) vec +-- | Concatenates two slices. Equivalent to mappend {-# INLINE sliceConcat #-} sliceConcat :: Slice a -> Slice b -> Slice c sliceConcat (Slice a) (Slice b) = Slice (a U.++ b)+ -- Slice traversal+-- | Slice version of forM_ {-# INLINE sliceForM_ #-} sliceForM_ :: Monad m => Slice c -> (Entity c -> m b) -> m () sliceForM_ (Slice vec) ma = U.forM_ vec (ma . Entity) +-- | Slice version of forM {-# INLINE sliceForM #-} sliceForM :: Monad m => Slice c -> (Entity c -> m a) -> m [a] sliceForM (Slice vec) ma = traverse (ma . Entity) (U.toList vec) +-- | Iterates over a slice, and reads the components of the Slice's type argument. {-# INLINE sliceForMC #-} sliceForMC :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c,Safe c) -> System w a) -> System w [a] sliceForMC (Slice vec) sys = do@@ -53,6 +59,7 @@ r <- liftIO$ explGet s e sys (Entity e, Safe r) +-- | Iterates over a slice, and reads the components of the Slice's type argument. {-# INLINE sliceForMC_ #-} sliceForMC_ :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c,Safe c) -> System w a) -> System w () sliceForMC_ (Slice vec) sys = do@@ -61,14 +68,17 @@ r <- liftIO$ explGet s e sys (Entity e, Safe r) +-- | Slice version of mapM_ {-# INLINE sliceMapM_ #-} sliceMapM_ :: Monad m => (Entity c -> m a) -> Slice c -> m () sliceMapM_ ma (Slice vec) = U.mapM_ (ma . Entity) vec +-- | Slice version of mapM {-# INLINE sliceMapM #-} sliceMapM :: Monad m => (Entity c -> m a) -> Slice c -> m [a] sliceMapM ma (Slice vec) = traverse (ma . Entity) (U.toList vec) +-- | Iterates over a slice, and reads the components of the Slice's type argument. {-# INLINE sliceMapMC #-} sliceMapMC :: forall w c a. (Store (Storage c), Has w c) => ((Entity c,Safe c) -> System w a) -> Slice c -> System w [a] sliceMapMC sys (Slice vec) = do@@ -77,6 +87,7 @@ r <- liftIO$ explGet s e sys (Entity e, Safe r) +-- | Iterates over a slice, and reads the components of the Slice's type argument. {-# INLINE sliceMapMC_ #-} sliceMapMC_ :: forall w c a. (Store (Storage c), Has w c) => ((Entity c, Safe c) -> System w a) -> Slice c -> System w () sliceMapMC_ sys vec = sliceForMC_ vec sys
src/Apecs/Stores.hs view
@@ -27,6 +27,8 @@ import Apecs.Types +-- | A map from Data.Intmap.Strict. O(n log(n)) for most operations.+-- Yields safe runtime representations of type @Maybe c@. newtype Map c = Map (IORef (M.IntMap c)) instance Initializable (Map c) where type InitArgs (Map c) = ()@@ -65,8 +67,12 @@ {-# INLINE explCimapM_ #-} {-# INLINE explCimapM #-} +-- | Class for flags, used by @Set@ to yield runtime representations. class Flag c where flag :: c++-- | A store that keeps membership, but holds no values.+-- Produces @flag@ runtime values. newtype Set c = Set (IORef S.IntSet) instance Initializable (Set c) where type InitArgs (Set c) = ()@@ -105,11 +111,11 @@ {-# INLINE explCmap #-} {-# INLINE explModify #-} +-- | Constant value. Not very practical, but fun to write. newtype Const c = Const c instance Initializable (Const c) where type InitArgs (Const c) = c initStoreWith c = return$ Const c- instance GlobalRW (Const c) c where explGlobalRead (Const c) = return c explGlobalWrite _ _ = return ()@@ -129,6 +135,8 @@ explModify _ _ _ = return () explCmap _ _ = return () +-- | Global value.+-- Must be given an initial value upon construction. newtype Global c = Global (IORef c) instance Initializable (Global c) where type InitArgs (Global c) = c@@ -142,11 +150,11 @@ {-# INLINE explGlobalWrite #-} {-# INLINE explGlobalModify #-} +-- | A cache around another store.+-- The wrapped store must produce safe representations using Maybe.+-- Note that iterating over a cache is linear in its size, so large, sparsely populated caches will actually decrease performance. data Cache (n :: Nat) s =- Cache Int -- | Size- (UM.IOVector Int) -- | Tags- (VM.IOVector (Stores s)) -- | Members- s -- | Writeback+ Cache Int (UM.IOVector Int) (VM.IOVector (Stores s)) s instance (KnownNat n, Initializable s) => Initializable (Cache n s) where type InitArgs (Cache n s) = (InitArgs s)@@ -264,8 +272,12 @@ -- For Enums, toIndex = fromEnum class Bounded a => ToIndex a where toIndex :: a -> Int+-- | A query to an IndexTable by an explicit index newtype ByIndex a = ByIndex Int+-- | A query to an IndexTable by a reference component newtype ByComponent c = ByComponent c+-- | A table that keeps a hashtable of indices along with its writes.+-- TODO: Benchmark? hashing function as argument? data IndexTable s = IndexTable { table :: VM.IOVector S.IntSet , wrapped :: s
src/Apecs/System.hs view
@@ -91,35 +91,41 @@ imapM sys = do s :: Storage c <- getStore explImapM s (sys . Entity) +-- | Maps a pure function over all components {-# INLINE cmap #-} cmap :: forall world c. (IsRuntime c, Has world c) => (c -> c) -> System world () cmap f = do s :: Storage c <- getStore liftIO$ explCmap s f +-- | mapM_ version of cmap {-# INLINE cmapM_ #-} cmapM_ :: forall w c. (Has w c, IsRuntime c) => (c -> System w ()) -> System w () cmapM_ sys = do s :: Storage c <- getStore explCmapM_ s sys +-- | indexed cmapM_, also gives the current entity. {-# INLINE cimapM_ #-} cimapM_ :: forall w c. (Has w c, IsRuntime c) => ((Entity c, c) -> System w ()) -> System w () cimapM_ sys = do s :: Storage c <- getStore explCimapM_ s (\(e,c) -> sys (Entity e,c)) +-- | mapM version of cmap. Can be used to get a list of entities {-# INLINE cmapM #-} cmapM :: forall w c a. (Has w c, IsRuntime c) => (c -> System w a) -> System w [a] cmapM sys = do s :: Storage c <- getStore explCmapM s sys +-- | indexed cmapM, also gives the current entity. {-# INLINE cimapM #-} cimapM :: forall w c a. (Has w c, IsRuntime c) => ((Entity c, c) -> System w a) -> System w [a] cimapM sys = do s :: Storage c <- getStore explCimapM s (\(e,c) -> sys (Entity e,c)) +-- | Maps a function that might delete its components cmap' :: forall world c. (Has world c, IsRuntime c) => (c -> Safe c) -> System world () cmap' f = do s :: Storage c <- getStore@@ -173,22 +179,26 @@ explSetMaybe sw e (getSafe . f . Safe $ r) +-- | Performs a query {-# INLINE slice #-} slice :: forall w c q. (Query q (Storage c), Has w c) => q -> System w (Slice c) slice q = do s :: Storage c <- getStore liftIO$ Slice <$> explSlice s q +-- | Reads a global value {-# INLINE readGlobal #-} readGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => System w c readGlobal = do s :: Storage c <- getStore liftIO$ explGlobalRead s +-- | Writes a global value {-# INLINE writeGlobal #-} writeGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => c -> System w () writeGlobal c = do s :: Storage c <- getStore liftIO$ explGlobalWrite s c +-- | Modifies a global value {-# INLINE modifyGlobal #-} modifyGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => (c -> c) -> System w () modifyGlobal f = do s :: Storage c <- getStore
src/Apecs/Types.hs view
@@ -34,7 +34,9 @@ -- Storage types -- | Common for every storage. Represents a container that can be initialized. class Initializable s where+ -- | The initialization argument required by this store type InitArgs s+ -- Initialize the store with its initialization arguments. initStoreWith :: InitArgs s -> IO s -- | A store that is indexed by entities.@@ -68,8 +70,10 @@ -- | Class of storages that associates components with entities. class HasMembers s => Store s where- type SafeRW s -- ^ Return type for safe reads/writes to the store- type Stores s -- ^ The type of components stored by this Store+ -- | Return type for safe reads writes to the store+ type SafeRW s+ -- | The type of components stored by this Store+ type Stores s -- | Unsafe index to the store. Undefined if the component does not exist explGetUnsafe :: s -> Int -> IO (Stores s) -- | Retrieves a component from the store@@ -121,9 +125,8 @@ x :: Stores s <- liftIO$ explGetUnsafe s ety sys (ety,x) -type Runtime c = Stores (Storage c) -- | A constraint that indicates that the runtime representation of @c@ is @c@-type IsRuntime c = (Store (Storage c), Runtime c ~ c)+type IsRuntime c = (Store (Storage c), Stores (Storage c) ~ c) -- | Class of storages for global values class GlobalRW s c where {-# MINIMAL explGlobalRead, explGlobalWrite #-}@@ -135,16 +138,20 @@ explGlobalModify s f = do r <- explGlobalRead s explGlobalWrite s (f r) --- Query+-- | Classes of queries @q@ that can be performed on a store @s@. class Query q s where+ -- | Returns a slice of the results of the query explSlice :: s -> q -> IO (U.Vector Int) +-- | Query that returns all members, equivalent to @members@ data All = All instance HasMembers s => Query All s where {-# INLINE explSlice #-} explSlice s _ = explMembers s -class Cast a b where cast :: a -> b+-- | Casts for entities and slices+class Cast a b where+ cast :: a -> b instance Cast (Entity a) (Entity b) where {-# INLINE cast #-} cast (Entity ety) = Entity ety
src/Apecs/Util.hs view
@@ -30,29 +30,36 @@ initStore :: (Initializable s, InitArgs s ~ ()) => IO s initStore = initStoreWith () +-- | Secretly just an int in a newtype newtype EntityCounter = EntityCounter Int deriving (Num, Eq, Show) instance Component EntityCounter where type Storage EntityCounter = Global EntityCounter +-- | Initialize an EntityCounter initCounter :: IO (Storage EntityCounter) initCounter = initStoreWith (EntityCounter 0) +-- | Bumps the EntityCounter and yields its value {-# INLINE nextEntity #-} nextEntity :: Has w EntityCounter => System w (Entity ()) nextEntity = do EntityCounter n <- readGlobal writeGlobal (EntityCounter (n+1)) return (Entity n) +-- | Writes the given components to a new entity, and yields that entity {-# INLINE newEntity #-} newEntity :: (IsRuntime c, Has w c, Has w EntityCounter) => c -> System w (Entity c) newEntity c = do ety <- nextEntity- set (cast ety) c+ set ety c return (cast ety) +-- | Explicitly invoke the garbage collector runGC :: System w () runGC = liftIO performMajorGC +-- | Sequentially performs a series of queries and concatenates their result.+-- Especially useful when iterating over an IndexTable newtype ConcatQueries q = ConcatQueries [q] instance Query q s => Query (ConcatQueries q) s where explSlice s (ConcatQueries qs) = mconcat <$> traverse (explSlice s) qs