@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -fno-warn-orphans #-}
1module ProjectM36.Attribute where
2module ProjectM36.Attribute where
2import ProjectM36.Base
3import ProjectM36.Base
3import ProjectM36.Error
4import ProjectM36.Error
@@ -10,16 +11,45 @@ import qualified Data.Map as M
10import Data.Either
11import Data.Either
12arity :: Attributes -> Int
13arity :: Attributes -> Int
13−arity = V.length
14+arity a = V.length (attributesVec a)
16+instance Semigroup Attributes where
18+ case joinAttributes attrsA attrsB of
19+ Left err -> error (show err)
20+ Right attrs' -> attrs'
22+instance Monoid Attributes where
23+ mempty = Attributes mempty mempty
15emptyAttributes :: Attributes
25emptyAttributes :: Attributes
16−emptyAttributes = V.empty
26+emptyAttributes = mempty
18null :: Attributes -> Bool
28null :: Attributes -> Bool
19−null = V.null
29+null a = V.null (attributesVec a)
31+singleton :: Attribute -> Attributes
32+singleton attr = Attributes (V.singleton attr) (HS.singleton attr)
34+toList :: Attributes -> [Attribute]
35+toList attrs = V.toList (attributesVec attrs)
21attributesFromList :: [Attribute] -> Attributes
37attributesFromList :: [Attribute] -> Attributes
22−attributesFromList = V.fromList -- . L.nub --too expensive
38+attributesFromList attrsL = Attributes vec hset
40+ vec = if length attrsL == HS.size hset then
41+ --fast path- no duplicates
44+ --duplicate detected, uniqueify while maintaining original ordering
46+ hset = HS.fromList attrsL
47+ uniquedL = fst $ foldr (\attr acc@(l,s) ->
48+ if HS.member attr s then
51+ (l ++ [attr], HS.insert attr s))
24attributeName :: Attribute -> AttributeName
54attributeName :: Attribute -> AttributeName
25attributeName (Attribute name _) = name
55attributeName (Attribute name _) = name
@@ -28,17 +58,16 @@ atomType :: Attribute -> AtomType
28atomType (Attribute _ atype) = atype
58atomType (Attribute _ atype) = atype
30atomTypes :: Attributes -> V.Vector AtomType
60atomTypes :: Attributes -> V.Vector AtomType
31−atomTypes = V.map atomType
61+atomTypes attrs = V.map atomType (attributesVec attrs)
33atomTypesList :: Attributes -> [AtomType]
63atomTypesList :: Attributes -> [AtomType]
34atomTypesList = V.toList . atomTypes
64atomTypesList = V.toList . atomTypes
36−--hm- no error-checking here
37addAttribute :: Attribute -> Attributes -> Attributes
66addAttribute :: Attribute -> Attributes -> Attributes
38−addAttribute attr attrs = attrs `V.snoc` attr
67+addAttribute attr attrs = attrs <> singleton attr
40--if some attribute names overlap but the types do not, then spit back an error
69--if some attribute names overlap but the types do not, then spit back an error
41−joinAttributes :: Attributes -> Attributes -> Either RelationalError Attributes
70+{-joinAttributes :: Attributes -> Attributes -> Either RelationalError Attributes
42joinAttributes attrs1 attrs2 | V.length uniqueOverlappingAttributes /= V.length overlappingAttributes = Left (TupleAttributeTypeMismatchError overlappingAttributes)
71joinAttributes attrs1 attrs2 | V.length uniqueOverlappingAttributes /= V.length overlappingAttributes = Left (TupleAttributeTypeMismatchError overlappingAttributes)
43 | V.length overlappingAttrsDifferentTypes > 0 = Left (TupleAttributeTypeMismatchError overlappingAttrsDifferentTypes)
72 | V.length overlappingAttrsDifferentTypes > 0 = Left (TupleAttributeTypeMismatchError overlappingAttrsDifferentTypes)
44 | otherwise = Right $ vectorUniqueify (attrs1 V.++ attrs2)
73 | otherwise = Right $ vectorUniqueify (attrs1 V.++ attrs2)
@@ -47,20 +76,47 @@ joinAttributes attrs1 attrs2 | V.length uniqueOverlappingAttributes /= V.length
47 attrNames2 = V.map attributeName attrs2
76 attrNames2 = V.map attributeName attrs2
48 uniqueOverlappingAttributes = vectorUniqueify overlappingAttributes
77 uniqueOverlappingAttributes = vectorUniqueify overlappingAttributes
49 overlappingAttributes = V.filter (`V.elem` attrs2) attrs1
78 overlappingAttributes = V.filter (`V.elem` attrs2) attrs1
80+joinAttributes :: Attributes -> Attributes -> Either RelationalError Attributes
81+joinAttributes attrs1 attrs2 =
82+ if S.size overlappingNames == 0 then -- fast path, no overlapping names
84+ else if attributesForNames overlappingNames attrs1 == attributesForNames overlappingNames attrs2 then -- check that atomtypes match
85+ pure (concated vectorUniqueify)
87+ --special handling to validate that overlapping names have the same atom types
88+ Left (TupleAttributeTypeMismatchError (attributesForNames overlappingNames attrs1))
90+ nameSet1 = attributeNameSet attrs1
91+ nameSet2 = attributeNameSet attrs2
92+ overlappingNames = S.intersection nameSet1 nameSet2
93+ concated f = Attributes (f (attributesVec attrs1 <> attributesVec attrs2)) (attributesSet attrs1 <> attributesSet attrs2)
51addAttributes :: Attributes -> Attributes -> Attributes
95addAttributes :: Attributes -> Attributes -> Attributes
52−addAttributes = (V.++)
96+addAttributes = (<>)
98+member :: Attribute -> Attributes -> Bool
99+member attr attrs = HS.member attr (attributesSet attrs)
54deleteAttributeName :: AttributeName -> Attributes -> Attributes
101deleteAttributeName :: AttributeName -> Attributes -> Attributes
55−deleteAttributeName attrName = V.filter (\attr -> attributeName attr /= attrName)
102+deleteAttributeName attrName attrs = deleteAttributeNames (S.singleton attrName) attrs
104+deleteAttributeNames :: S.Set AttributeName -> Attributes -> Attributes
105+deleteAttributeNames attrNames attrs = Attributes vec hset
107+ vec = V.filter attrFilter (attributesVec attrs)
108+ hset = HS.filter attrFilter (attributesSet attrs)
109+ attrFilter attr = S.notMember (attributeName attr) attrNames
57renameAttribute :: AttributeName -> Attribute -> Attribute
111renameAttribute :: AttributeName -> Attribute -> Attribute
58renameAttribute newAttrName (Attribute _ typeo) = Attribute newAttrName typeo
112renameAttribute newAttrName (Attribute _ typeo) = Attribute newAttrName typeo
60renameAttributes :: AttributeName -> AttributeName -> Attributes -> Attributes
114renameAttributes :: AttributeName -> AttributeName -> Attributes -> Attributes
61−renameAttributes oldAttrName newAttrName = V.map renamer
115+renameAttributes oldAttrName newAttrName attrs = Attributes vec hset
117+ vec = V.map renamer (attributesVec attrs)
118+ hset = HS.map renamer (attributesSet attrs)
63− renamer attr = if attributeName attr == oldAttrName then
119+ renamer attr = if attributeName attr == oldAttrName then
64 renameAttribute newAttrName attr
120 renameAttribute newAttrName attr
@@ -71,7 +127,7 @@ atomTypeForAttributeName attrName attrs = do
71 return atype
127 return atype
73attributeForName :: AttributeName -> Attributes -> Either RelationalError Attribute
129attributeForName :: AttributeName -> Attributes -> Either RelationalError Attribute
74−attributeForName attrName attrs = case V.find (\attr -> attributeName attr == attrName) attrs of
130+attributeForName attrName attrs = case V.find (\attr -> attributeName attr == attrName) (attributesVec attrs) of
75 Nothing -> Left (NoSuchAttributeNamesError (S.singleton attrName))
131 Nothing -> Left (NoSuchAttributeNamesError (S.singleton attrName))
76 Just attr -> Right attr
132 Just attr -> Right attr
@@ -89,15 +145,18 @@ projectionAttributesForNames names attrsIn =
89 missingNames = attributeNamesNotContained names (S.fromList (V.toList (attributeNames attrsIn)))
145 missingNames = attributeNamesNotContained names (S.fromList (V.toList (attributeNames attrsIn)))
91attributesForNames :: S.Set AttributeName -> Attributes -> Attributes
147attributesForNames :: S.Set AttributeName -> Attributes -> Attributes
92−attributesForNames attrNameSet = V.filter filt
148+attributesForNames attrNameSet attrs = Attributes vec hset
151+ vec = V.filter filt (attributesVec attrs)
152+ hset = HS.filter filt (attributesSet attrs)
94 filt attr = S.member (attributeName attr) attrNameSet
153 filt attr = S.member (attributeName attr) attrNameSet
96attributeNameSet :: Attributes -> S.Set AttributeName
155attributeNameSet :: Attributes -> S.Set AttributeName
97−attributeNameSet attrVec = S.fromList $ V.toList $ V.map (\(Attribute name _) -> name) attrVec
156+attributeNameSet attrs = S.fromList $ V.toList $ V.map (\(Attribute name _) -> name) (attributesVec attrs)
99attributeNames :: Attributes -> V.Vector AttributeName
158attributeNames :: Attributes -> V.Vector AttributeName
100−attributeNames = V.map attributeName
159+attributeNames attrs = V.map attributeName (attributesVec attrs)
102--checks if set s1 is wholly contained in the set s2
161--checks if set s1 is wholly contained in the set s2
103attributesContained :: Attributes -> Attributes -> Bool
162attributesContained :: Attributes -> Attributes -> Bool
@@ -118,42 +177,70 @@ attributeNamesNotContained subset superset = S.filter (`S.notMember` superset) s
119-- useful for display
178-- useful for display
120orderedAttributes :: Attributes -> [Attribute]
179orderedAttributes :: Attributes -> [Attribute]
121−orderedAttributes attrs = L.sortBy (\a b -> attributeName a `compare` attributeName b) (V.toList attrs)
180+orderedAttributes attrs = L.sortBy (\a b -> attributeName a `compare` attributeName b) (V.toList (attributesVec attrs))
123orderedAttributeNames :: Attributes -> [AttributeName]
182orderedAttributeNames :: Attributes -> [AttributeName]
124orderedAttributeNames attrs = map attributeName (orderedAttributes attrs)
183orderedAttributeNames attrs = map attributeName (orderedAttributes attrs)
126-- take two attribute sets and return an attribute set with the attributes which do not match
185-- take two attribute sets and return an attribute set with the attributes which do not match
186+--this is the function which benefits the most from the HashSet representation- this turned up in the insert performance test
127attributesDifference :: Attributes -> Attributes -> Attributes
187attributesDifference :: Attributes -> Attributes -> Attributes
128−attributesDifference attrsA attrsB = V.fromList $ diff (V.toList attrsA) (V.toList attrsB)
188+{-attributesDifference attrsA attrsB = V.fromList $ diff (V.toList attrsA) (V.toList attrsB)
130 diff a b = (a L.\\ b) ++ (b L.\\ a)
190 diff a b = (a L.\\ b) ++ (b L.\\ a)
192+attributesDifference attrsA attrsB =
193+ if attributesSet attrsA == attributesSet attrsB then
198+ hset = HS.difference setA setB <> HS.difference setB setA
199+ setA = attributesSet attrsA
200+ setB = attributesSet attrsB
201+ vec = V.filter (\attr -> HS.member attr hset) (attributesVec attrsA <> attributesVec attrsB)
132vectorUniqueify :: (Hash.Hashable a, Eq a) => V.Vector a -> V.Vector a
203vectorUniqueify :: (Hash.Hashable a, Eq a) => V.Vector a -> V.Vector a
133vectorUniqueify vecIn = V.fromList $ HS.toList $ HS.fromList $ V.toList vecIn
204vectorUniqueify vecIn = V.fromList $ HS.toList $ HS.fromList $ V.toList vecIn
135--check that each attribute only appears once
206--check that each attribute only appears once
136verifyAttributes :: Attributes -> Either RelationalError Attributes
207verifyAttributes :: Attributes -> Either RelationalError Attributes
137−verifyAttributes attrs = if collapsedAttrs /= attrs then
208+verifyAttributes attrs =
209+ if vecSet == attributesSet attrs then
138− Left (TupleAttributeTypeMismatchError (attributesDifference collapsedAttrs attrs))
212+ Left (TupleAttributeTypeMismatchError diffAttrs)
142− collapsedAttrs = vectorUniqueify attrs
214+ vecSet = V.foldr' HS.insert HS.empty (attributesVec attrs)
143−
215+ diffSet = HS.difference vecSet (attributesSet attrs) <> HS.difference (attributesSet attrs) vecSet
216+ diffAttrs = Attributes (V.fromList (HS.toList diffSet)) diffSet
218+--used in Generics derivation for ADTs without named attributes- not to be used elsewhere
219+--drop first n attributes from vector representation
220+drop :: Int -> Attributes -> Attributes
221+drop c attrs = Attributes vec hset
223+ droppedAttrs = V.take c (attributesVec attrs)
224+ vec = V.drop c (attributesVec attrs)
225+ hset = HS.filter (`V.notElem` droppedAttrs) hset
227+-- use this in preference to (==) when the attribute ordering matters such as during tuple unions
144attributesEqual :: Attributes -> Attributes -> Bool
228attributesEqual :: Attributes -> Attributes -> Bool
145−attributesEqual attrs1 attrs2 = V.null (attributesDifference attrs1 attrs2)
229+attributesEqual a b = attributesVec a == attributesVec b
147attributesAsMap :: Attributes -> M.Map AttributeName Attribute
231attributesAsMap :: Attributes -> M.Map AttributeName Attribute
148−attributesAsMap attrs = (M.fromList . V.toList) (V.map (\attr -> (attributeName attr, attr)) attrs)
232+attributesAsMap attrs = V.foldr' (\attr acc -> M.insert (attributeName attr) attr acc) mempty (attributesVec attrs)
150-- | Left-biased union of attributes.
235-- | Left-biased union of attributes.
151union :: Attributes -> Attributes -> Attributes
236union :: Attributes -> Attributes -> Attributes
152−union attrsA attrsB = V.fromList (M.elems unioned)
237+union attrsA attrsB = Attributes vec hset
154− unioned = M.union (attributesAsMap attrsA) (attributesAsMap attrsB)
239+ hset = HS.union (attributesSet attrsA) (attributesSet attrsB)
240+ vec = HS.foldr (flip V.snoc) mempty hset
156intersection :: Attributes -> Attributes -> Attributes
242intersection :: Attributes -> Attributes -> Attributes
157−intersection attrsA attrsB = V.fromList (M.elems intersected)
243+intersection attrsA attrsB = Attributes vec hset
159− intersected = M.intersection (attributesAsMap attrsA) (attributesAsMap attrsB)
245+ hset = HS.intersection (attributesSet attrsA) (attributesSet attrsB)
246+ vec = HS.foldr (flip V.snoc) mempty hset