Selaa lähdekoodia

Merge branch 'master' into feat/format-matcher

# Conflicts:
#	include/jvalidate/forward.h
#	include/jvalidate/validator.h
Sam Jaffe 2 viikkoa sitten
vanhempi
commit
d3e5492e1f

+ 1 - 1
include/jvalidate/detail/reference_manager.h

@@ -460,7 +460,7 @@ private:
    * - All of the enabled keywords in the vocabulary
    * - The list of enabled vocabulary metaschema (used for is_format_assertion)
    */
-  auto extract_keywords(ObjectAdapter auto const & vocabularies) const
+  auto extract_keywords(ObjectAdapter<A> auto const & vocabularies) const
       -> std::pair<std::unordered_map<std::string, bool>, std::unordered_set<std::string>> {
     std::unordered_map<std::string, bool> keywords;
     std::unordered_set<std::string> vocab_docs;

+ 1 - 2
include/jvalidate/detail/simple_adapter.h

@@ -131,8 +131,7 @@ private:
  */
 template <typename JSON, typename CRTP = AdapterFor<JSON>> class SimpleAdapter : public Adapter {
 public:
-  static constexpr bool is_mutable =
-      not std::is_const_v<JSON> && MutableObject<decltype(std::declval<CRTP>().as_object())>;
+  static constexpr bool is_mutable = not std::is_const_v<JSON> && HasMutableObject<CRTP>;
   using value_type = std::remove_const_t<JSON>;
 
 public:

+ 15 - 9
include/jvalidate/forward.h

@@ -1,8 +1,10 @@
 #pragma once
 
+#include <concepts>
 #include <functional>
 #include <iosfwd>
 #include <string>
+#include <string_view>
 #include <type_traits>
 #include <variant>
 
@@ -109,19 +111,19 @@ concept ObjectIterator =
       { it->second } -> std::convertible_to<adapter::Adapter const &>;
     };
 
-template <typename A>
+template <typename A, typename Reentrant>
 concept ArrayAdapter = requires(A const a) {
   { a.size() } -> std::convertible_to<std::size_t>;
-  { a[0UL] } -> std::convertible_to<adapter::Adapter const &>;
+  { a[0UL] } -> std::same_as<Reentrant>;
   { a.begin() } -> ArrayIterator;
   { a.end() } -> ArrayIterator;
 };
 
-template <typename A>
+template <typename A, typename Reentrant>
 concept ObjectAdapter = requires(A const a) {
   { a.size() } -> std::convertible_to<std::size_t>;
   { a.contains("") } -> std::same_as<bool>;
-  { a[""] } -> std::convertible_to<adapter::Adapter const &>;
+  { a[""] } -> std::same_as<Reentrant>;
   { a.begin() } -> ObjectIterator;
   { a.end() } -> ObjectIterator;
 };
@@ -144,18 +146,21 @@ concept Adapter = std::is_base_of_v<adapter::Adapter, A> && requires(A const a)
   { a.as_integer() } -> std::convertible_to<int64_t>;
   { a.as_number() } -> std::convertible_to<double>;
   { a.as_number() } -> std::floating_point;
-  { a.as_object() } -> ObjectAdapter;
-  { a.as_array() } -> ArrayAdapter;
+  { a.as_object() } -> ObjectAdapter<A>;
+  { a.as_array() } -> ArrayAdapter<A>;
 
   { a.array_size() } -> std::convertible_to<size_t>;
   { a.object_size() } -> std::convertible_to<size_t>;
 };
 
-template <typename A>
-concept MutableObject = ObjectAdapter<A> && requires(A const a) {
+template <typename A, typename Reentrant>
+concept MutableObject = ObjectAdapter<A, Reentrant> && requires(A const a) {
   { a.assign("", std::declval<adapter::Const>()) };
 };
 
+template <typename A>
+concept HasMutableObject = MutableObject<decltype(std::declval<A>().as_object()), A>;
+
 /**
  * @brief An extension of Adapter that is capable of altering the underlying
  * JSON node. In general, that means that a non-const ref is captured when
@@ -169,11 +174,12 @@ template <typename A>
 concept MutableAdapter = Adapter<A> && requires(A const a) {
   { a.assign(std::declval<adapter::Const>()) };
   { a.assign(std::declval<adapter::Adapter>()) };
-  { a.as_object() } -> MutableObject;
+  { a.as_object() } -> MutableObject<A>;
 };
 
 template <typename R>
 concept RegexEngine = requires(R & engine) {
+  { R::engine_name() } -> std::convertible_to<std::string_view>;
   { R::is_regex("") } -> std::same_as<bool>;
   { engine.search("" /* pattern */, "" /* text */) } -> std::same_as<bool>;
 };

+ 4 - 0
include/jvalidate/regex.h

@@ -30,6 +30,8 @@ private:
   std::unordered_map<std::string, std::regex> cache_;
 
 public:
+  static std::string_view engine_name() { return "std::regex[ECMAScript]"; }
+
   static bool is_regex(std::string_view regex) {
     try {
       [[maybe_unused]] std::regex _{std::string(regex)};
@@ -51,6 +53,8 @@ private:
   std::unordered_map<std::string, std::unique_ptr<icu::RegexPattern>> cache_;
 
 public:
+  static std::string_view engine_name() { return "icu::RegexPattern"; }
+
   static bool is_regex(std::string_view regex) {
     icu::UnicodeString const ucs = icu::UnicodeString::fromUTF8(icu::StringPiece(regex));
 

+ 2 - 1
include/jvalidate/validation_visitor.h

@@ -291,6 +291,7 @@ public:
     NOOP_UNLESS_TYPE(String);
 
     std::string const str = document.as_string();
+    annotate(regex_.engine_name());
     if (regex_.search(cons.regex, str)) {
       return result(Status::Accept, "string matches pattern /", cons.regex, "/");
     }
@@ -696,7 +697,7 @@ private:
   // Optimization to avoid running string-like objects through a
   // std::stringstream in fmtlist.
   static std::string fmt(S const & str) {
-    return str;
+    return std::string(str);
   }
 
   // Format va_args into a single string to annotate or mark an error message