+\f
+/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
+ * with minimatch_destroy(). */
+void
+minimatch_init(struct minimatch *dst, const struct match *src)
+{
+ minimask_init(&dst->mask, &src->wc);
+ miniflow_init_with_minimask(&dst->flow, &src->flow, &dst->mask);
+}
+
+/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
+ * with minimatch_destroy(). */
+void
+minimatch_clone(struct minimatch *dst, const struct minimatch *src)
+{
+ miniflow_clone(&dst->flow, &src->flow);
+ minimask_clone(&dst->mask, &src->mask);
+}
+
+/* Initializes 'dst' with the data in 'src', destroying 'src'. The caller must
+ * eventually free 'dst' with minimatch_destroy(). */
+void
+minimatch_move(struct minimatch *dst, struct minimatch *src)
+{
+ miniflow_move(&dst->flow, &src->flow);
+ minimask_move(&dst->mask, &src->mask);
+}
+
+/* Frees any memory owned by 'match'. Does not free the storage in which
+ * 'match' itself resides; the caller is responsible for that. */
+void
+minimatch_destroy(struct minimatch *match)
+{
+ miniflow_destroy(&match->flow);
+ minimask_destroy(&match->mask);
+}
+
+/* Initializes 'dst' as a copy of 'src'. */
+void
+minimatch_expand(const struct minimatch *src, struct match *dst)
+{
+ miniflow_expand(&src->flow, &dst->flow);
+ minimask_expand(&src->mask, &dst->wc);
+}
+
+/* Returns true if 'a' and 'b' match the same packets, false otherwise. */
+bool
+minimatch_equal(const struct minimatch *a, const struct minimatch *b)
+{
+ return (miniflow_equal(&a->flow, &b->flow)
+ && minimask_equal(&a->mask, &b->mask));
+}
+
+/* Returns a hash value for 'match', given 'basis'. */
+uint32_t
+minimatch_hash(const struct minimatch *match, uint32_t basis)
+{
+ return miniflow_hash(&match->flow, minimask_hash(&match->mask, basis));
+}
+
+/* Returns true if 'target' satisifies 'match', that is, if each bit for which
+ * 'match' specifies a particular value has the correct value in 'target'.
+ *
+ * This function is equivalent to miniflow_equal_flow_in_minimask(&match->flow,
+ * target, &match->mask) but it is faster because of the invariant that
+ * match->flow.map and match->mask.map are the same. */
+bool
+minimatch_matches_flow(const struct minimatch *match,
+ const struct flow *target)
+{
+ const uint32_t *target_u32 = (const uint32_t *) target;
+ const uint32_t *flowp = match->flow.values;
+ const uint32_t *maskp = match->mask.masks.values;
+ uint64_t map;
+
+ for (map = match->flow.map; map; map = zero_rightmost_1bit(map)) {
+ if ((*flowp++ ^ target_u32[raw_ctz(map)]) & *maskp++) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Returns a hash value for the bits of range [start, end) in 'minimatch',
+ * given 'basis'.
+ *
+ * The hash values returned by this function are the same as those returned by
+ * flow_hash_in_minimask_range(), only the form of the arguments differ. */
+uint32_t
+minimatch_hash_range(const struct minimatch *match, uint8_t start, uint8_t end,
+ uint32_t *basis)
+{
+ unsigned int offset;
+ const uint32_t *p, *q;
+ uint32_t hash = *basis;
+ int n, i;
+
+ n = count_1bits(miniflow_get_map_in_range(&match->mask.masks, start, end,
+ &offset));
+ q = match->mask.masks.values + offset;
+ p = match->flow.values + offset;
+
+ for (i = 0; i < n; i++) {
+ hash = mhash_add(hash, p[i] & q[i]);
+ }
+ *basis = hash; /* Allow continuation from the unfinished value. */
+ return mhash_finish(hash, (offset + n) * 4);
+}
+
+/* Appends a string representation of 'match' to 's'. If 'priority' is
+ * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
+void
+minimatch_format(const struct minimatch *match, struct ds *s,
+ unsigned int priority)
+{
+ struct match megamatch;
+
+ minimatch_expand(match, &megamatch);
+ match_format(&megamatch, s, priority);
+}
+
+/* Converts 'match' to a string and returns the string. If 'priority' is
+ * different from OFP_DEFAULT_PRIORITY, includes it in the string. The caller
+ * must free the string (with free()). */
+char *
+minimatch_to_string(const struct minimatch *match, unsigned int priority)
+{
+ struct match megamatch;
+
+ minimatch_expand(match, &megamatch);
+ return match_to_string(&megamatch, priority);
+}