< prev index next >

src/hotspot/share/utilities/stringUtils.cpp

Print this page
rev 59083 : DRAFT 8236522: NonTearable marker interface for inline classes to enforce atomicity

@@ -22,10 +22,11 @@
  *
  */
 
 #include "precompiled.hpp"
 #include "utilities/debug.hpp"
+#include "utilities/ostream.hpp"
 #include "utilities/stringUtils.hpp"
 
 int StringUtils::replace_no_expand(char* string, const char* from, const char* to) {
   int replace_count = 0;
   size_t from_len = strlen(from);

@@ -63,5 +64,283 @@
     }
   }
 
   return 2.0 * (double) hit / (double) total;
 }
+
+class StringMatcher {
+ public:
+  typedef int getc_function_t(const char* &source, const char* limit);
+  const getc_function_t* _pattern_getc;
+  const getc_function_t* _string_getc;
+
+  StringMatcher(getc_function_t pattern_getc,
+                getc_function_t string_getc)
+    : _pattern_getc(pattern_getc),
+      _string_getc(string_getc)
+  { }
+
+  enum {  // special results from _pattern_getc
+    string_match_comma  = -0x100 + ',',
+    string_match_star   = -0x100 + '*',
+    string_match_eos    = -0x100 + '\0'
+  };
+
+ private:
+  const char*
+  skip_anchor_word(const char* match,
+                   const char* match_end,
+                   int anchor_length,
+                   const char* pattern,
+                   const char* pattern_end) {
+    assert(pattern < pattern_end && anchor_length > 0, "");
+    const char* begp = pattern;
+    int ch1 = _pattern_getc(begp, pattern_end);
+    // note that begp is now advanced over ch1
+    assert(ch1 > 0, "regular char only");
+    const char* matchp = match;
+    const char* limitp = match_end - anchor_length;
+    while (matchp <= limitp) {
+      int mch = _string_getc(matchp, match_end);
+      if (mch == ch1) {
+        const char* patp = begp;
+        const char* anchorp = matchp;
+        while (patp < pattern_end) {
+          char ch = _pattern_getc(patp, pattern_end);
+          char mch = _string_getc(anchorp, match_end);
+          if (mch != ch) {
+            anchorp = NULL;
+            break;
+          }
+        }
+        if (anchorp != NULL) {
+          return anchorp;  // Found a full copy of the anchor.
+        }
+        // That did not work, so restart the search for ch1.
+      }
+    }
+    return NULL;
+  }
+
+ public:
+  bool string_match(const char* pattern,
+                    const char* string) {
+    return string_match(pattern, pattern + strlen(pattern),
+                        string, string + strlen(string));
+  }
+  bool string_match(const char* pattern, const char* pattern_end,
+                    const char* string, const char* string_end) {
+    const char* patp = pattern;
+    switch (_pattern_getc(patp, pattern_end)) {
+    case string_match_eos:
+      return false;  // Empty pattern is always false.
+    case string_match_star:
+      if (patp == pattern_end) {
+        return true;   // Lone star pattern is always true.
+      }
+      break;
+    }
+    patp = pattern;  // Reset after lookahead.
+    const char* matchp = string;  // NULL if failing
+    for (;;) {
+      int ch = _pattern_getc(patp, pattern_end);
+      switch (ch) {
+      case string_match_eos:
+      case string_match_comma:
+        // End of a list item; see if it's a match.
+        if (matchp == string_end) {
+          return true;
+        }
+        if (ch == string_match_comma) {
+          // Get ready to match the next item.
+          matchp = string;
+          continue;
+        }
+        return false;  // End of all items.
+
+      case string_match_star:
+        if (matchp != NULL) {
+          // Wildcard:  Parse out following anchor word and look for it.
+          const char* begp = patp;
+          const char* endp = patp;
+          int anchor_len = 0;
+          for (;;) {
+            // get as many following regular characters as possible
+            endp = patp;
+            ch = _pattern_getc(patp, pattern_end);
+            if (ch <= 0) {
+              break;
+            }
+            anchor_len += 1;
+          }
+          // Anchor word [begp..endp) does not contain ch, so back up.
+          // Now do an eager match to the anchor word, and commit to it.
+          patp = endp;
+          if (ch == string_match_eos ||
+              ch == string_match_comma) {
+            // Anchor word is at end of pattern, so treat it as a fixed pattern.
+            const char* limitp = (matchp + strlen(matchp)) - anchor_len;
+            matchp = limitp;
+            patp = begp;
+            // Resume normal scanning at the only possible match position.
+            continue;
+          }
+          // Find a floating occurrence of the anchor and continue matching.
+          // Note:  This is greedy; there is no backtrack here.  Good enough.
+          matchp = skip_anchor_word(matchp, string_end, anchor_len, begp, endp);
+        }
+        continue;
+      }
+      // Normal character.
+      if (matchp != NULL) {
+        int mch = _string_getc(matchp, string_end);
+        if (mch != ch) {
+          matchp = NULL;
+        }
+      }
+    }
+  }
+};
+
+// Match a wildcarded class list to a proposed class name (in internal form).
+// Commas or newlines separate multiple possible matches; stars are shell-style wildcards.
+class ClassListMatcher : public StringMatcher {
+ public:
+  ClassListMatcher()
+    : StringMatcher(pattern_list_getc, class_name_getc)
+  { }
+
+ private:
+  static int pattern_list_getc(const char* &pattern_ptr,
+                               const char* pattern_end) {
+    if (pattern_ptr == pattern_end) {
+      return string_match_eos;
+    }
+    int ch = (unsigned char) *pattern_ptr++;
+    switch (ch) {
+    case ' ': case '\t': case '\n': case '\r':
+    case ',':
+      // End of list item.
+      for (;;) {
+        switch (*pattern_ptr) {
+        case ' ': case '\t': case '\n': case '\r':
+        case ',':
+          pattern_ptr += 1;  // Collapse multiple commas or spaces.
+          continue;
+        }
+        break;
+      }
+      return string_match_comma;
+
+    case '*':
+      // Wildcard, matching any number of chars.
+      while (*pattern_ptr == '*') {
+        pattern_ptr += 1;  // Collapse multiple stars.
+      }
+      return string_match_star;
+
+    case '.':
+      ch = '/';   // Look for internal form of package separator
+      break;
+
+    case '\\':
+      // Superquote in pattern escapes * , whitespace, and itself.
+      if (pattern_ptr < pattern_end) {
+        ch = (unsigned char) *pattern_ptr++;
+      }
+      break;
+    }
+
+    assert(ch > 0, "regular char only");
+    return ch;
+  }
+
+  static int class_name_getc(const char* &name_ptr,
+                             const char* name_end) {
+    if (name_ptr == name_end) {
+      return string_match_eos;
+    }
+    int ch = (unsigned char) *name_ptr++;
+    if (ch == '.') {
+      ch = '/';   // Normalize to internal form of package separator
+    }
+    return ch;  // plain character
+  }
+};
+
+static bool class_list_match_sane();
+
+bool StringUtils::class_list_match(const char* class_pattern_list,
+                                   const char* class_name) {
+  assert(class_list_match_sane(), "");
+  if (class_pattern_list == NULL || class_name == NULL || class_name[0] == '\0')
+    return false;
+  ClassListMatcher clm;
+  return clm.string_match(class_pattern_list, class_name);
+}
+
+#ifdef ASSERT
+static void
+class_list_match_sane(const char* pat, const char* str, bool result = true) {
+  if (result) {
+    assert(StringUtils::class_list_match(pat, str), "%s ~ %s", pat, str);
+  } else {
+    assert(!StringUtils::class_list_match(pat, str), "%s !~ %s", pat, str);
+  }
+}
+
+static bool
+class_list_match_sane() {
+  static bool done = false;
+  if (done)  return true;
+  done = true;
+  class_list_match_sane("foo", "foo");
+  class_list_match_sane("foo,", "foo");
+  class_list_match_sane(",foo,", "foo");
+  class_list_match_sane("bar,foo", "foo");
+  class_list_match_sane("bar,foo,", "foo");
+  class_list_match_sane("*", "foo");
+  class_list_match_sane("foo.bar", "foo/bar");
+  class_list_match_sane("foo/bar", "foo.bar");
+  class_list_match_sane("\\foo", "foo");
+  class_list_match_sane("\\*foo", "*foo");
+  const char* foo = "foo!";
+  char buf[100], buf2[100];
+  const int m = strlen(foo);
+  for (int n = 0; n <= 1; n++) {
+    for (int a = -1; a <= 1; a++) {
+      for (int i = 0; i <= m; i++) {
+        for (int j = i; j <= m; j++) {
+          if (j == i && j > 0)  continue;
+          for (int k = j; k <= m; k++) {
+            if (k == j && k > i)  continue;
+            for (int l = k; l <= m; l++) {
+              if (l == k && l > j)  continue;
+              char* bp = &buf[0];
+              strncpy(bp, foo + 0, i - 0); bp += i - 0;
+              *bp++ = '*';
+              strncpy(bp, foo + j, k - j); bp += k - j;
+              *bp++ = '*';
+              strncpy(bp, foo + l, m - l); bp += m - l;
+              if (n) {
+                *bp++ = 'N';  // make it fail
+              }
+              *bp++ = '\0';
+              if (a != 0) {
+                if (a < 0) {
+                  strcpy(buf2, buf);
+                  strcat(buf, "X*, ");
+                  strcat(buf, buf2);
+                } else {
+                  strcat(buf, ", Y");
+                }
+              }
+              class_list_match_sane(buf, foo, !n);
+            }
+          }
+        }
+      }
+    }
+  }
+  return true;
+}
+#endif //ASSERT
< prev index next >