Hi klimek,

Refactor VariantMatcher to use a tagged union.
It supports "Single" and "Polymorphic". Will support more in the future.

http://llvm-reviews.chandlerc.com/D1446

Files:
  include/clang/ASTMatchers/Dynamic/VariantValue.h
  lib/ASTMatchers/Dynamic/VariantValue.cpp
Index: include/clang/ASTMatchers/Dynamic/VariantValue.h
===================================================================
--- include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -69,7 +69,7 @@
   void reset();
 
   /// \brief Whether the matcher is null.
-  bool isNull() const { return List.empty(); }
+  bool isNull() const { return Tag == RT_Nothing; }
 
   /// \brief Return a single matcher, if there is no ambiguity.
   ///
@@ -86,8 +86,8 @@
   /// result would be ambigous and false is returned.
   template <class T>
   bool hasTypedMatcher() const {
-    return getTypedMatcher(
-        &ast_matchers::internal::Matcher<T>::canConstructFrom) != NULL;
+    return hasTypedMatcher(
+        &ast_matchers::internal::Matcher<T>::canConstructFrom);
   }
 
   /// \brief Wrap the correct matcher as a \c Matcher<T>.
@@ -109,13 +109,38 @@
   std::string getTypeAsString() const;
 
 private:
+  void setSingle(const DynTypedMatcher &Matcher);
+  void setPolymorphic(ArrayRef<const DynTypedMatcher *> Matchers);
+
+  /// \brief Returns whether the matcher passes the callback.
+  bool hasTypedMatcher(
+      bool (*CanConstructCallback)(const DynTypedMatcher &)) const;
+
   /// \brief Returns the matcher that passes the callback.
   ///
-  /// Returns NULL if no matcher passes the test, or if more than one do.
-  const DynTypedMatcher *
-  getTypedMatcher(bool (*CanConstructCallback)(const DynTypedMatcher &)) const;
+  /// For the polymorphic case, it returns NULL if no matcher passes the test,
+  /// or if more than one do.
+  const DynTypedMatcher *getTypedMatcher(
+      bool (*CanConstructCallback)(const DynTypedMatcher &)) const;
+
+  enum RepresentationTag {
+    RT_Nothing,
+    RT_Single,
+    RT_Polymorphic
+  };
+  RepresentationTag Tag;
 
-  std::vector<const DynTypedMatcher *> List;
+  struct SingleRep {
+    OwningPtr<const DynTypedMatcher> Matcher;
+  };
+  struct PolymorphicRep {
+    std::vector<const DynTypedMatcher *> Matchers;
+    ~PolymorphicRep();
+  };
+  union {
+    SingleRep *AsSingle;
+    PolymorphicRep *AsPolymorphic;
+  };
 };
 
 /// \brief Variant value class.
Index: lib/ASTMatchers/Dynamic/VariantValue.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -21,24 +21,26 @@
 namespace ast_matchers {
 namespace dynamic {
 
-VariantMatcher::VariantMatcher() : List() {}
+VariantMatcher::PolymorphicRep::~PolymorphicRep() {
+  llvm::DeleteContainerPointers(Matchers);
+}
+
+VariantMatcher::VariantMatcher() : Tag(RT_Nothing) {}
 
 VariantMatcher::VariantMatcher(const VariantMatcher& Other) {
   *this = Other;
 }
 
 VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
   VariantMatcher Out;
-  Out.List.push_back(Matcher.clone());
+  Out.setSingle(Matcher);
   return Out;
 }
 
 VariantMatcher
 VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) {
   VariantMatcher Out;
-  for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
-    Out.List.push_back(Matchers[i]->clone());
-  }
+  Out.setPolymorphic(Matchers);
   return Out;
 }
 
@@ -49,41 +51,116 @@
 VariantMatcher &VariantMatcher::operator=(const VariantMatcher &Other) {
   if (this == &Other) return *this;
   reset();
-  for (size_t i = 0, e = Other.List.size(); i != e; ++i) {
-    List.push_back(Other.List[i]->clone());
+  switch (Other.Tag) {
+  case RT_Nothing:
+    break;
+  case RT_Single:
+    setSingle(*Other.AsSingle->Matcher);
+    break;
+  case RT_Polymorphic:
+    setPolymorphic(Other.AsPolymorphic->Matchers);
+    break;
   }
   return *this;
 }
 
 bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
-  if (List.size() != 1) return false;
-  Out = List[0];
-  return true;
+  switch (Tag) {
+  case RT_Nothing:
+    return false;
+  case RT_Single:
+    Out = AsSingle->Matcher.get();
+    return true;
+  case RT_Polymorphic:
+    if (AsPolymorphic->Matchers.size() != 1)
+      return false;
+    Out = AsPolymorphic->Matchers[0];
+    return true;
+  }
 }
 
 void VariantMatcher::reset() {
-  llvm::DeleteContainerPointers(List);
+  switch (Tag) {
+  case RT_Nothing:
+    break;
+  case RT_Single:
+    delete AsSingle;
+    break;
+  case RT_Polymorphic:
+    delete AsPolymorphic;
+    break;
+  }
+  Tag = RT_Nothing;
+}
+
+void VariantMatcher::setSingle(const DynTypedMatcher &Matcher) {
+  assert(Tag == RT_Nothing);
+  Tag = RT_Single;
+  AsSingle = new SingleRep;
+  AsSingle->Matcher.reset(Matcher.clone());
+}
+
+void
+VariantMatcher::setPolymorphic(ArrayRef<const DynTypedMatcher *> Matchers) {
+  assert(Tag == RT_Nothing);
+  Tag = RT_Polymorphic;
+  AsPolymorphic = new PolymorphicRep;
+  for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
+    AsPolymorphic->Matchers.push_back(Matchers[i]->clone());
+  }
 }
 
 std::string VariantMatcher::getTypeAsString() const {
-  std::string Inner;
-  for (size_t I = 0, E = List.size(); I != E; ++I) {
-    if (I != 0) Inner += "|";
-    Inner += List[I]->getSupportedKind().asStringRef();
+  switch (Tag) {
+  case RT_Nothing:
+    return "<Nothing>";
+  case RT_Single:
+    return (Twine("Matcher<") +
+            AsSingle->Matcher->getSupportedKind().asStringRef() + ">").str();
+  case RT_Polymorphic: {
+    std::string Inner;
+    for (size_t i = 0, e = AsPolymorphic->Matchers.size(); i != e; ++i) {
+      if (i != 0) Inner += "|";
+      Inner += AsPolymorphic->Matchers[i]->getSupportedKind().asStringRef();
+    }
+    return (Twine("Matcher<") + Inner + ">").str();
+  }
+  }
+}
+
+bool VariantMatcher::hasTypedMatcher(
+    bool (*CanConstructCallback)(const DynTypedMatcher &)) const {
+  switch (Tag) {
+  case RT_Nothing:
+    return false;
+  case RT_Single:
+    return CanConstructCallback(*AsSingle->Matcher);
+  case RT_Polymorphic: {
+    bool FoundOne = false;
+    for (size_t i = 0, e = AsPolymorphic->Matchers.size(); i != e; ++i) {
+      if (CanConstructCallback(*AsPolymorphic->Matchers[i])) {
+        if (FoundOne)
+          return false;
+        FoundOne = true;
+      }
+    }
+    return FoundOne;
+  }
   }
-  return (Twine("Matcher<") + Inner + ">").str();
 }
 
 const DynTypedMatcher *VariantMatcher::getTypedMatcher(
     bool (*CanConstructCallback)(const DynTypedMatcher &)) const {
-  const DynTypedMatcher *Out = NULL;
-  for (size_t i = 0, e = List.size(); i != e; ++i) {
-    if (CanConstructCallback(*List[i])) {
-      if (Out) return NULL;
-      Out = List[i];
+  switch (Tag) {
+  case RT_Nothing: return NULL;
+  case RT_Single: return AsSingle->Matcher.get();
+  case RT_Polymorphic:
+    for (size_t i = 0, e = AsPolymorphic->Matchers.size(); i != e; ++i) {
+      if (CanConstructCallback(*AsPolymorphic->Matchers[i]))
+        return AsPolymorphic->Matchers[i];
     }
+    return NULL;
   }
-  return Out;
 }
 
 VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to