 
     defstruct [:source, :matchspec, :compiled]
 
-    @opaque t :: %__MODULE__{source: String.t(), matchspec: :ets.match_spec(), compiled: boolean}
+    @opaque t :: %__MODULE__{
+              source: String.t(),
+              matchspec: :ets.match_spec() | :ets.comp_match_spec(),
+              compiled: boolean
+            }
+
+    @doc false
+    @spec new(String.t(), :ets.match_spec()) :: t
+    def new(source, spec) do
+      %__MODULE__{source: source, matchspec: spec, compiled: false}
+    end
+
+    @doc false
+    @spec compile(t) :: t
+    def compile(%__MODULE__{matchspec: spec} = requirement) do
+      %{requirement | matchspec: :ets.match_spec_compile(spec), compiled: true}
+    end
+
+    @doc false
+    @spec match?(t, tuple) :: boolean
+    def match?(%__MODULE__{matchspec: spec, compiled: true}, matchable_pattern) do
+      matches = :ets.match_spec_run([matchable_pattern], spec)
+      matches != []
+    end
+
+    def match?(%__MODULE__{matchspec: spec, compiled: false}, matchable_pattern) do
+      {:ok, result} = :ets.test_ms(matchable_pattern, spec)
+      result != false
+    end
   end
 
   defmodule InvalidRequirementError do

  def parse_requirement!(string) when is_binary(string) do
    case Version.Parser.parse_requirement(string) do
      {:ok, spec} ->
        %Requirement{source: string, matchspec: spec, compiled: false}

      :error ->
        raise InvalidRequirementError, string

    match?(version, parse_requirement!(requirement), opts)
  end

  def match?(version, requirement, opts) do
    allow_pre = Keyword.get(opts, :allow_pre, true)
    matchable_pattern = to_matchable(version, allow_pre)

    Requirement.match?(requirement, matchable_pattern)
  end

  @doc """
