/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FRUIT_META_SET_H #define FRUIT_META_SET_H #include #include #include #include namespace fruit { namespace impl { namespace meta { // Set ::= Vector, with no duplicates. using EmptySet = Vector<>; template using ToSet1 = Vector; template using ToSet2 = Vector; using IsInSet = IsInVector; // If S is a set with elements (T1, ..., Tn) this calculates // F(InitialValue, F(T1, F(..., F(Tn) ...))). // If S is EmptySet this returns InitialValue. using FoldSet = FoldVector; // If S is a set with elements (T1, ..., Tn) this calculates // Combine(F(T1), Combine(F(T2),..., F(Tn) ...)). // // `Combine' must be associative, and CombineIdentity must be an identity value wrt Combine. // Use this instead of FoldSet when possible, it shares more sub-instances when invoked multiple // times with similar sets. struct FoldSetWithCombine { template struct apply { using type = FoldVector(TransformVector(S, F), Combine, CombineIdentity); }; }; // Converts a set (T1,...,Tn) to a set (F(T1), ..., F(Tn)). // F(T1), ..., F(Tn) must be distinct. using TransformSet = TransformVector; using SetSize = VectorSize; using AddToSetUnchecked = PushFront; struct AddToSet { template struct apply { using type = If(IsInSet(T, S), S, AddToSetUnchecked(S, T)); }; }; // Checks if S1 is contained in S2. struct IsContained { template struct apply { struct Helper { template struct apply { using type = And(CurrentResult, IsInSet(T, S2)); }; }; using type = FoldVector(S1, Helper, Bool); }; }; // Checks if S1 is disjoint from S2. struct IsDisjoint { template struct apply { struct Helper { template struct apply { using type = Or(CurrentResult, IsInSet(T, S2)); }; }; using type = Not(FoldVector(S1, Helper, Bool)); }; }; struct IsEmptySet { template struct apply { using type = Bool; }; }; template <> struct IsEmptySet::apply> { using type = Bool; }; using SetToVector = Identity; // The vector must have no duplicates. using VectorToSetUnchecked = Identity; struct SetDifference { template struct apply { struct Helper { template struct apply { using type = If(IsInSet(T, S2), CurrentResult, AddToSetUnchecked(CurrentResult, T)); }; }; using type = FoldSet(S1, Helper, EmptySet); }; }; struct SetIntersection { template struct apply { struct Helper { template struct apply { using type = If(IsInSet(T, S2), AddToSetUnchecked(CurrentResult, T), CurrentResult); }; }; using type = If(GreaterThan(SetSize(S1), SetSize(S2)), SetIntersection(S2, S1), FoldSet(S1, Helper, EmptySet)); }; }; struct SetUnion { template struct apply { using type = If(GreaterThan(SetSize(S1), SetSize(S2)), SetUnion(S2, S1), FoldSet(SetDifference(S1, S2), AddToSetUnchecked, S2)); }; }; using SetUncheckedUnion = ConcatVectors; struct IsSameSet { template struct apply { using type = And(IsContained(S1, S2), IsContained(S2, S1)); }; }; // Returns an arbitrary element from the given set (that must be non-empty). struct GetArbitrarySetElement { template struct apply; template struct apply> { using type = T; }; }; } // namespace meta } // namespace impl } // namespace fruit #endif // FRUIT_META_SET_H