kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/common/regex.cc (about)

     1  /*
     2   * Copyright 2020 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  #include "kythe/cxx/common/regex.h"
    18  
    19  #include <memory>
    20  #include <utility>
    21  #include <vector>
    22  
    23  #include "absl/base/no_destructor.h"
    24  #include "absl/log/check.h"
    25  #include "absl/log/log.h"
    26  #include "absl/status/status.h"
    27  #include "absl/status/statusor.h"
    28  #include "absl/strings/string_view.h"
    29  #include "re2/re2.h"
    30  
    31  namespace kythe {
    32  namespace {
    33  
    34  std::shared_ptr<const RE2> DefaultRegex() {
    35    static const absl::NoDestructor<std::shared_ptr<const RE2>> kEmpty{
    36        std::make_shared<RE2>("")};
    37    return *kEmpty;
    38  }
    39  
    40  std::shared_ptr<const RE2::Set> DefaultSet() {
    41    static const absl::NoDestructor<std::shared_ptr<const RE2::Set>> kEmpty{[] {
    42      auto set = std::make_shared<RE2::Set>(RE2::Options(), RE2::UNANCHORED);
    43      set->Compile();
    44      return set;
    45    }()};
    46    return *kEmpty;
    47  }
    48  
    49  RE2::Set CheckCompiled(RE2::Set set) {
    50    RE2::Set::ErrorInfo error;
    51    if (!set.Match("", nullptr, &error)) {
    52      if (error.kind == RE2::Set::kNotCompiled) {
    53        DLOG(FATAL) << "Uncompiled RE2::Set passed to RegexSet";
    54        CHECK(set.Compile()) << "Failed to compile RE2::Set";
    55      }
    56    }
    57    return set;
    58  }
    59  }  // namespace
    60  
    61  absl::StatusOr<Regex> Regex::Compile(absl::string_view pattern,
    62                                       const RE2::Options& options) {
    63    std::shared_ptr<const RE2> re = std::make_shared<RE2>(pattern, options);
    64    if (!re->ok()) {
    65      return absl::InvalidArgumentError(re->error());
    66    }
    67    return Regex(std::move(re));
    68  }
    69  
    70  Regex::Regex() : re_(DefaultRegex()) {}
    71  
    72  Regex::Regex(const RE2& re)
    73      : re_(std::make_shared<RE2>(re.pattern(), re.options())) {
    74    CHECK(re_->ok()) << "Cannot initialize Regex from invalid RE2: "
    75                     << re_->error();
    76  }
    77  
    78  Regex::Regex(Regex&& other) noexcept : re_(std::move(other.re_)) {
    79    other.re_ = DefaultRegex();
    80  }
    81  
    82  Regex& Regex::operator=(Regex&& other) noexcept {
    83    re_ = std::move(other.re_);
    84    other.re_ = DefaultRegex();
    85    return *this;
    86  }
    87  
    88  RegexSet::RegexSet() : set_(DefaultSet()) {}
    89  RegexSet::RegexSet(RE2::Set set)
    90      : set_(std::make_shared<RE2::Set>(CheckCompiled(std::move(set)))) {}
    91  
    92  RegexSet::RegexSet(RegexSet&& other) noexcept : set_(std::move(other.set_)) {
    93    other.set_ = DefaultSet();
    94  }
    95  
    96  RegexSet& RegexSet::operator=(RegexSet&& other) noexcept {
    97    set_ = std::move(other.set_);
    98    other.set_ = DefaultSet();
    99    return *this;
   100  }
   101  
   102  absl::StatusOr<std::vector<int>> RegexSet::ExplainMatch(
   103      absl::string_view value) const {
   104    RE2::Set::ErrorInfo error;
   105    std::vector<int> matches;
   106    if (set_->Match(value, &matches, &error)) {
   107      return matches;
   108    }
   109    matches.clear();
   110    switch (error.kind) {
   111      case RE2::Set::kNoError:
   112        return matches;  // Empty match == no error, but no matches.
   113      case RE2::Set::kNotCompiled:
   114        // Shouldn't happen.
   115        return absl::InternalError("Match() called on uncompiled Set");
   116      case RE2::Set::kOutOfMemory:
   117        return absl::ResourceExhaustedError("Match() ran out of memory");
   118      case RE2::Set::kInconsistent:
   119        return absl::InternalError("RE2::Match() had inconsistent result");
   120    }
   121    return absl::UnknownError("");
   122  }
   123  
   124  }  // namespace kythe