PageRenderTime 2109ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 1ms

/std/src/Foreign/Hoppy/Generator/Std/Set.hs

https://gitlab.com/lingnan/hoppy
Haskell | 213 lines | 154 code | 17 blank | 42 comment | 3 complexity | 303eaa351984fb3c41143beab19157ad MD5 | raw file
  1. -- This file is part of Hoppy.
  2. --
  3. -- Copyright 2015-2016 Bryan Gardiner <bog@khumba.net>
  4. --
  5. -- Licensed under the Apache License, Version 2.0 (the "License");
  6. -- you may not use this file except in compliance with the License.
  7. -- You may obtain a copy of the License at
  8. --
  9. -- http://www.apache.org/licenses/LICENSE-2.0
  10. --
  11. -- Unless required by applicable law or agreed to in writing, software
  12. -- distributed under the License is distributed on an "AS IS" BASIS,
  13. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. -- See the License for the specific language governing permissions and
  15. -- limitations under the License.
  16. {-# LANGUAGE CPP #-}
  17. -- | Bindings for @std::set@.
  18. module Foreign.Hoppy.Generator.Std.Set (
  19. Options (..),
  20. defaultOptions,
  21. Contents (..),
  22. instantiate,
  23. instantiate',
  24. toExports,
  25. ) where
  26. import Control.Monad (forM, when)
  27. #if !MIN_VERSION_base(4,8,0)
  28. import Data.Monoid (mconcat)
  29. #endif
  30. import Foreign.Hoppy.Generator.Language.Haskell (
  31. HsTypeSide (HsHsSide),
  32. addImports,
  33. cppTypeToHsTypeAndUse,
  34. indent,
  35. ln,
  36. prettyPrint,
  37. sayLn,
  38. saysLn,
  39. toHsCastMethodName,
  40. toHsDataTypeName,
  41. toHsClassEntityName,
  42. )
  43. import Foreign.Hoppy.Generator.Spec
  44. import Foreign.Hoppy.Generator.Spec.ClassFeature (
  45. ClassFeature (Assignable, Comparable, Copyable),
  46. classAddFeatures,
  47. )
  48. import Foreign.Hoppy.Generator.Std (ValueConversion (ConvertPtr, ConvertValue))
  49. import Foreign.Hoppy.Generator.Std.Internal (includeHelper)
  50. import Foreign.Hoppy.Generator.Std.Iterator
  51. import Foreign.Hoppy.Generator.Types
  52. -- | Options for instantiating the set classes.
  53. data Options = Options
  54. { optSetClassFeatures :: [ClassFeature]
  55. -- ^ Additional features to add to the @std::set@ class. Sets are always
  56. -- 'Assignable', 'Comparable', and 'Copyable', but you may want to add
  57. -- 'Foreign.Hoppy.Generator.Spec.ClassFeature.Equatable' if your value type
  58. -- supports those.
  59. , optValueConversion :: Maybe ValueConversion
  60. }
  61. -- | The default options have no additional 'ClassFeature's.
  62. defaultOptions :: Options
  63. defaultOptions = Options [] Nothing
  64. -- | A set of instantiated set classes.
  65. data Contents = Contents
  66. { c_set :: Class -- ^ @std::set\<T>@
  67. , c_iterator :: Class -- ^ @std::set\<T>::iterator@
  68. }
  69. -- | @instantiate className t tReqs@ creates a set of bindings for an
  70. -- instantiation of @std::set@ and associated types (e.g. iterators). In the
  71. -- result, the 'c_set' class has an external name of @className@, and the
  72. -- iterator class is further suffixed with @\"Iterator\"@.
  73. instantiate :: String -> Type -> Reqs -> Contents
  74. instantiate setName t tReqs = instantiate' setName t tReqs defaultOptions
  75. -- | 'instantiate' with additional options.
  76. instantiate' :: String -> Type -> Reqs -> Options -> Contents
  77. instantiate' setName t tReqs opts =
  78. let reqs = mconcat
  79. [ tReqs
  80. , reqInclude $ includeHelper "set.hpp"
  81. , reqInclude $ includeStd "set"
  82. ]
  83. iteratorName = setName ++ "Iterator"
  84. set =
  85. (case optValueConversion opts of
  86. Nothing -> id
  87. Just conversion -> addAddendumHaskell $ makeAddendum conversion) $
  88. addReqs reqs $
  89. classAddFeatures (Assignable : Comparable : Copyable : optSetClassFeatures opts) $
  90. makeClass (ident1T "std" "set" [t]) (Just $ toExtName setName) []
  91. [ mkCtor "new" []
  92. , mkConstMethod "begin" [] $ toGcT $ objT iterator
  93. , mkMethod "clear" [] voidT
  94. , mkConstMethod "count" [t] sizeT
  95. -- TODO count
  96. , mkConstMethod "empty" [] boolT
  97. , mkConstMethod "end" [] $ toGcT $ objT iterator
  98. -- equalRange: find is good enough.
  99. , mkMethod' "erase" "erase" [objT iterator] voidT
  100. , mkMethod' "erase" "eraseRange" [objT iterator, objT iterator] voidT
  101. , mkMethod "find" [t] $ toGcT $ objT iterator
  102. -- TODO Replace these with a single version that returns a (toGcT std::pair).
  103. , makeFnMethod (ident2 "hoppy" "set" "insert") "insert"
  104. MNormal Nonpure [refT $ objT set, t] boolT
  105. , makeFnMethod (ident2 "hoppy" "set" "insertAndGetIterator") "insertAndGetIterator"
  106. MNormal Nonpure [refT $ objT set, t] $ toGcT $ objT iterator
  107. -- lower_bound: find is good enough.
  108. , mkConstMethod' "max_size" "maxSize" [] sizeT
  109. , mkConstMethod "size" [] sizeT
  110. , mkMethod "swap" [refT $ objT set] voidT
  111. -- upper_bound: find is good enough.
  112. ]
  113. -- Set iterators are always constant, because modifying elements in place
  114. -- will break the internal order of the set.
  115. iterator =
  116. addReqs reqs $
  117. makeBidirectionalIterator Constant (Just t) $
  118. makeClass (identT' [("std", Nothing), ("set", Just [t]), ("iterator", Nothing)])
  119. (Just $ toExtName iteratorName) [] []
  120. -- The addendum for the set class contains HasContents and FromContents
  121. -- instances.
  122. makeAddendum conversion = do
  123. addImports $ mconcat [hsImport1 "Prelude" "($)",
  124. hsImportForPrelude,
  125. hsImportForRuntime]
  126. when (conversion == ConvertValue) $
  127. addImports $ mconcat [hsImport1 "Prelude" "(=<<)"]
  128. hsDataNameConst <- toHsDataTypeName Const set
  129. hsDataName <- toHsDataTypeName Nonconst set
  130. [hsValueTypeConst, hsValueType] <- forM [Const, Nonconst] $ \cst ->
  131. cppTypeToHsTypeAndUse HsHsSide $
  132. (case conversion of
  133. ConvertPtr -> ptrT
  134. ConvertValue -> id) $
  135. case cst of
  136. Const -> constT t
  137. Nonconst -> t
  138. setConstCast <- toHsCastMethodName Const set
  139. setEmpty <- toHsClassEntityName set "empty"
  140. setBegin <- toHsClassEntityName set "begin"
  141. setEnd <- toHsClassEntityName set "end"
  142. iterEq <- toHsClassEntityName iterator OpEq
  143. iterGetConst <- toHsClassEntityName iterator "getConst"
  144. iterPrev <- toHsClassEntityName iterator "prev"
  145. -- Generate const and nonconst HasContents instances.
  146. ln
  147. saysLn ["instance HoppyFHR.HasContents ", hsDataNameConst,
  148. " (", prettyPrint hsValueTypeConst, ") where"]
  149. indent $ do
  150. sayLn "toContents this' = do"
  151. indent $ do
  152. saysLn ["empty' <- ", setEmpty, " this'"]
  153. sayLn "if empty' then HoppyP.return [] else do"
  154. indent $ do
  155. saysLn ["begin' <- ", setBegin, " this'"]
  156. saysLn ["iter' <- ", setEnd, " this'"]
  157. sayLn "go' iter' begin' []"
  158. sayLn "where"
  159. indent $ do
  160. sayLn "go' iter' begin' acc' = do"
  161. indent $ do
  162. saysLn ["stop' <- ", iterEq, " iter' begin'"]
  163. sayLn "if stop' then HoppyP.return acc' else do"
  164. indent $ do
  165. saysLn ["_ <- ", iterPrev, " iter'"]
  166. saysLn ["value' <- ",
  167. case conversion of
  168. ConvertPtr -> ""
  169. ConvertValue -> "HoppyFHR.decode =<< ",
  170. iterGetConst, " iter'"]
  171. sayLn "go' iter' begin' $ value':acc'"
  172. ln
  173. saysLn ["instance HoppyFHR.HasContents ", hsDataName,
  174. " (", prettyPrint hsValueTypeConst, ") where"]
  175. indent $
  176. saysLn ["toContents = HoppyFHR.toContents . ", setConstCast]
  177. -- Only generate a nonconst FromContents instance.
  178. ln
  179. saysLn ["instance HoppyFHR.FromContents ", hsDataName,
  180. " (", prettyPrint hsValueType, ") where"]
  181. indent $ do
  182. sayLn "fromContents values' = do"
  183. indent $ do
  184. setNew <- toHsClassEntityName set "new"
  185. setInsert <- toHsClassEntityName set "insert"
  186. saysLn ["set' <- ", setNew]
  187. saysLn ["HoppyP.mapM_ (", setInsert, " set') values'"]
  188. sayLn "HoppyP.return set'"
  189. in Contents
  190. { c_set = set
  191. , c_iterator = iterator
  192. }
  193. -- | Converts an instantiation into a list of exports to be included in a
  194. -- module.
  195. toExports :: Contents -> [Export]
  196. toExports m = map (ExportClass . ($ m)) [c_set, c_iterator]