src/util/graph_small_color_map.h
src/util/hash.h
src/util/hash_dynamic_bitset.h
+ src/util/insertion_ordered.h
src/util/math.h
src/util/multibit_build.cpp
src/util/multibit_build.h
#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/graph_range.h"
+#include "util/insertion_ordered.h"
#include "util/make_unique.h"
#include "util/order_check.h"
#include "util/target_info.h"
insert(&splitter_reports, base_graph[v].reports);
}
- /* find the targets of each source vertex; note the use of vectors to
+ /* find the targets of each source vertex; insertion_ordered_map used to
* preserve deterministic ordering */
- vector<RoseInVertex> sources;
- map<RoseInVertex, vector<RoseInVertex>> images;
+ insertion_ordered_map<RoseInVertex, vector<RoseInVertex>> images;
for (const RoseInEdge &e : ee) {
RoseInVertex src = source(e, vg);
RoseInVertex dest = target(e, vg);
- if (!contains(images, src)) {
- sources.push_back(src);
- }
images[src].push_back(dest);
remove_edge(e, vg);
}
map<vector<RoseInVertex>, vector<RoseInVertex>> verts_by_image;
- for (const auto &u : sources) {
- const auto &image = images[u];
+ for (const auto &m : images) {
+ const auto &u = m.first;
+ const auto &image = m.second;
if (contains(verts_by_image, image)) {
for (RoseInVertex v : verts_by_image[image]) {
static
void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
const CompileContext &cc) {
- vector<NGHolder *> seen_order;
- map<NGHolder *, vector<RoseInEdge>> infixes;
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> infixes;
for (const RoseInEdge &e : edges_range(g)) {
RoseInVertex s = source(e, g);
}
NGHolder *h = g[e].graph.get();
- if (!contains(infixes, h)) {
- seen_order.push_back(h);
- }
infixes[h].push_back(e);
}
- for (NGHolder *h : seen_order) {
- removeRedundantLiteralsFromInfix(*h, g, infixes[h], cc);
+ for (const auto &m : infixes) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
+ removeRedundantLiteralsFromInfix(*h, g, edges, cc);
}
}
STAGE_DEBUG_PRINTF("FIND BETTER PREFIXES\n");
RoseInVertex start = getStart(vg);
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> prefixes;
bool changed;
u32 gen = 0;
do {
DEBUG_PRINTF("gen %u\n", gen);
changed = false;
- vector<NGHolder *> seen_order;
- map<NGHolder *, vector<RoseInEdge> > prefixes;
+ prefixes.clear();
/* find prefixes */
for (const RoseInEdge &e : out_edges_range(start, vg)) {
assert(vg[target(e, vg)].type == RIV_LITERAL);
if (vg[e].graph) {
NGHolder *h = vg[e].graph.get();
- if (!contains(prefixes, h)) {
- seen_order.push_back(h);
- }
prefixes[h].push_back(e);
}
}
}
/* look for bad prefixes and try to split */
- for (NGHolder *h : seen_order) {
+ for (const auto &m : prefixes) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
depth max_width = findMaxWidth(*h);
if (willBeTransient(max_width, cc)
|| willBeAnchoredTable(max_width, cc.grey)) {
continue;
}
- changed = improvePrefix(*h, vg, prefixes[h], cc);
+ changed = improvePrefix(*h, vg, edges, cc);
}
} while (changed && gen++ < MAX_FIND_BETTER_PREFIX_GEN);
}
if (!cc.grey.violetExtractStrongLiterals) {
return;
}
+
STAGE_DEBUG_PRINTF("EXTRACT STRONG LITERALS\n");
- set<NGHolder *> stuck;
+ unordered_set<NGHolder *> stuck;
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> edges_by_graph;
bool changed;
+
do {
changed = false;
- vector<NGHolder *> seen_order;
- map<NGHolder *, vector<RoseInEdge> > edges_by_graph;
+ edges_by_graph.clear();
for (const RoseInEdge &ve : edges_range(vg)) {
if (vg[source(ve, vg)].type != RIV_LITERAL) {
continue;
}
+
if (vg[ve].graph) {
- if (!contains(edges_by_graph, vg[ve].graph.get())) {
- seen_order.push_back(vg[ve].graph.get());
- }
- edges_by_graph[vg[ve].graph.get()].push_back(ve);
+ NGHolder *h = vg[ve].graph.get();
+ edges_by_graph[h].push_back(ve);
}
}
return;
}
- for (NGHolder *g : seen_order) {
+ for (const auto &m : edges_by_graph) {
+ NGHolder *g = m.first;
+ const auto &edges = m.second;
if (contains(stuck, g)) {
DEBUG_PRINTF("already known to be bad\n");
continue;
}
- bool rv = extractStrongLiteral(*g, vg, edges_by_graph[g], cc);
+ bool rv = extractStrongLiteral(*g, vg, edges, cc);
if (rv) {
changed = true;
} else {
RoseInVertex start = getStart(vg);
- set<NGHolder *> weak;
- vector<NGHolder *> ordered_weak;
+ unordered_set<NGHolder *> weak;
for (RoseInVertex vv : adjacent_vertices_range(start, vg)) {
/* outfixes shouldn't have made it this far */
NGHolder *h = vg[e].graph.get();
DEBUG_PRINTF("'%s' guards %p\n", dumpString(vg[vv].s).c_str(), h);
- if (!contains(weak, h)) {
- weak.insert(h);
- ordered_weak.push_back(h);
- }
+ weak.insert(h);
}
}
- map<NGHolder *, vector<RoseInEdge> > weak_edges;
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> weak_edges;
for (const RoseInEdge &ve : edges_range(vg)) {
- if (contains(weak, vg[ve].graph.get())) {
- weak_edges[vg[ve].graph.get()].push_back(ve);
+ NGHolder *h = vg[ve].graph.get();
+ if (contains(weak, h)) {
+ weak_edges[h].push_back(ve);
}
}
- for (NGHolder *h : ordered_weak) {
- improveInfix(*h, vg, weak_edges[h], cc);
+ for (const auto &m : weak_edges) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
+ improveInfix(*h, vg, edges, cc);
}
}
STAGE_DEBUG_PRINTF("AVOID SUFFIXES\n");
RoseInVertex accept = getPrimaryAccept(vg);
- map<const NGHolder *, vector<RoseInEdge> > suffixes;
- vector<const NGHolder *> ordered_suffixes;
+
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> suffixes;
/* find suffixes */
for (const RoseInEdge &e : in_edges_range(accept, vg)) {
assert(vg[e].graph); /* non suffix paths should be wired to other
accepts */
const NGHolder *h = vg[e].graph.get();
- if (!contains(suffixes, h)) {
- ordered_suffixes.push_back(h);
- }
suffixes[h].push_back(e);
}
/* look at suffixes and try to split */
- for (const NGHolder *h : ordered_suffixes) {
- replaceSuffixWithInfix(*h, vg, suffixes[h], cc);
+ for (const auto &m : suffixes) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ replaceSuffixWithInfix(*h, vg, edges, cc);
}
}
return;
}
- map<const NGHolder *, vector<RoseInEdge> > right_edges;
- vector<const NGHolder *> ordered_graphs;
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
for (const RoseInEdge &ve : edges_range(vg)) {
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
const NGHolder *h = vg[ve].graph.get();
- if (!contains(right_edges, h)) {
- ordered_graphs.push_back(h);
- }
right_edges[h].push_back(ve);
}
}
- for (const NGHolder *h : ordered_graphs) {
- lookForDoubleCut(*h, right_edges[h], vg, cc.grey);
+ for (const auto &m : right_edges) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ lookForDoubleCut(*h, edges, vg, cc.grey);
}
}
return;
}
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
bool changed;
do {
changed = false;
- map<const NGHolder *, vector<RoseInEdge> > right_edges;
- vector<const NGHolder *> ordered_graphs;
+ right_edges.clear();
for (const RoseInEdge &ve : edges_range(vg)) {
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
const NGHolder *h = vg[ve].graph.get();
- if (!contains(right_edges, h)) {
- ordered_graphs.push_back(h);
- }
right_edges[h].push_back(ve);
}
}
- for (const NGHolder *h : ordered_graphs) {
- const vector<RoseInEdge> &ee = right_edges[h];
+ for (const auto &m : right_edges) {
+ const NGHolder *h = m.first;
+ const vector<RoseInEdge> &ee = m.second;
bool rv = lookForDoubleCut(*h, ee, vg, cc.grey);
if (!rv && h->kind != NFA_SUFFIX) {
rv = lookForTrailingLiteralDotStar(*h, ee, vg, cc.grey);
void lookForCleanEarlySplits(RoseInGraph &vg, const CompileContext &cc) {
u32 gen = 0;
- vector<RoseInVertex> prev = {getStart(vg)};
+ insertion_ordered_set<RoseInVertex> prev({getStart(vg)});
+ insertion_ordered_set<RoseInVertex> curr;
while (gen < MAX_DESIRED_CLEAN_SPLIT_DEPTH) {
- /* collect vertices in edge order for determinism */
- vector<RoseInVertex> curr;
- set<RoseInVertex> curr_seen;
+ curr.clear();
for (RoseInVertex u : prev) {
for (auto v : adjacent_vertices_range(u, vg)) {
- if (curr_seen.insert(v).second) {
- curr.push_back(v);
- }
+ curr.insert(v);
}
}
- map<const NGHolder *, vector<RoseInEdge>> rightfixes;
- vector<NGHolder *> ordered_graphs;
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> rightfixes;
for (RoseInVertex v : curr) {
for (const RoseInEdge &e : out_edges_range(v, vg)) {
if (vg[e].graph) {
NGHolder *h = vg[e].graph.get();
- if (!contains(rightfixes, h)) {
- ordered_graphs.push_back(h);
- }
rightfixes[h].push_back(e);
}
}
}
- for (const NGHolder *h : ordered_graphs) {
- lookForCleanSplit(*h, rightfixes[h], vg, cc);
+ for (const auto &m : rightfixes) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ lookForCleanSplit(*h, edges, vg, cc);
}
- prev = curr;
+ prev = std::move(curr);
gen++;
}
}
do {
changed = false;
DEBUG_PRINTF("added %u\n", added_count);
- map<const NGHolder *, vector<RoseInEdge> > edges_by_graph;
- vector<shared_ptr<NGHolder>> graphs;
+ insertion_ordered_map<shared_ptr<NGHolder>,
+ vector<RoseInEdge>> edges_by_graph;
for (const RoseInEdge &ve : edges_range(vg)) {
if (vg[ve].graph && !vg[ve].dfa) {
auto &h = vg[ve].graph;
- if (!contains(edges_by_graph, h.get())) {
- graphs.push_back(h);
- }
- edges_by_graph[h.get()].push_back(ve);
+ edges_by_graph[h].push_back(ve);
}
}
- for (auto &h : graphs) {
+ for (auto &m : edges_by_graph) {
+ auto &h = m.first;
if (contains(good, h)) {
continue;
}
continue;
}
- if (tryForEarlyDfa(*h, cc)
- && doEarlyDfa(rose, vg, *h, edges_by_graph[h.get()],
- final_chance, rm, cc)) {
+ const auto &edges = m.second;
+
+ if (tryForEarlyDfa(*h, cc) &&
+ doEarlyDfa(rose, vg, *h, edges, final_chance, rm, cc)) {
continue;
}
return false;
}
- if (splitForImplementability(vg, *h, edges_by_graph[h.get()], cc)) {
+ if (splitForImplementability(vg, *h, edges, cc)) {
added_count++;
if (added_count > MAX_IMPLEMENTABLE_SPLITS) {
DEBUG_PRINTF("added_count hit limit\n");
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
+#include "util/insertion_ordered.h"
#include "util/make_unique.h"
#include "util/noncopyable.h"
#include "util/order_check.h"
renumber_vertices(in);
assert(validateKinds(in));
- map<NGHolder *, vector<RoseInEdge> > graphs;
- vector<NGHolder *> ordered_graphs; // Stored in first-encounter order.
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> graphs;
for (const auto &e : edges_range(in)) {
if (!in[e].graph) {
NGHolder *h = in[e].graph.get();
assert(isCorrectlyTopped(*h));
- if (!contains(graphs, h)) {
- ordered_graphs.push_back(h);
- }
graphs[h].push_back(e);
}
- assert(ordered_graphs.size() == graphs.size());
-
vector<RoseInEdge> graph_edges;
- for (auto h : ordered_graphs) {
+ for (const auto &m : graphs) {
+ NGHolder *h = m.first;
if (!canImplementGraph(*h, prefilter, rm, cc)) {
return false;
}
- insert(&graph_edges, graph_edges.end(), graphs[h]);
+ insert(&graph_edges, graph_edges.end(), m.second);
}
/* we are now past the point of no return. We can start making irreversible
#include "util/container.h"
#include "util/fatbit_build.h"
#include "util/graph_range.h"
+#include "util/insertion_ordered.h"
#include "util/make_unique.h"
#include "util/multibit_build.h"
#include "util/noncopyable.h"
RoseGraph &g = tbi.g;
const CompileContext &cc = tbi.cc;
- map<left_id, set<PredTopPair> > infixTriggers;
- vector<left_id> order;
- unordered_map<left_id, vector<RoseVertex>> succs;
+ map<left_id, set<PredTopPair>> infixTriggers;
findInfixTriggers(tbi, &infixTriggers);
+ insertion_ordered_map<left_id, vector<RoseVertex>> succs;
+
if (cc.grey.allowTamarama && cc.streaming && !do_prefix) {
findExclusiveInfixes(tbi, bc, qif, infixTriggers, no_retrigger_queues);
}
}
}
- if (!contains(succs, leftfix)) {
- order.push_back(leftfix);
- }
-
succs[leftfix].push_back(v);
}
map<left_id, eager_info> eager;
- for (const left_id &leftfix : order) {
- const auto &left_succs = succs[leftfix];
+ for (const auto &m : succs) {
+ const left_id &leftfix = m.first;
+ const auto &left_succs = m.second;
rose_group squash_mask = tbi.rose_squash_masks.at(leftfix);
eager_info ei;
eager.clear();
}
- for (const left_id &leftfix : order) {
+ for (const auto &m : succs) {
+ const left_id &leftfix = m.first;
+ const auto &left_succs = m.second;
buildLeftfix(tbi, bc, do_prefix, qif.get_queue(), infixTriggers,
- no_retrigger_queues, eager_queues, eager, succs[leftfix],
+ no_retrigger_queues, eager_queues, eager, left_succs,
leftfix);
}
--- /dev/null
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UTIL_INSERTION_ORDERED_H
+#define UTIL_INSERTION_ORDERED_H
+
+/**
+ * \file
+ * \brief Insertion-ordered associative containers (set, map).
+ */
+
+#include "util/operators.h"
+#include "util/unordered.h"
+
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <boost/iterator/iterator_facade.hpp>
+
+namespace ue2 {
+
+namespace insertion_ordered_detail {
+
+// Iterator facade that wraps an underlying iterator, so that we get our
+// own iterator types.
+template<class WrappedIter, class Value>
+class iter_wrapper
+ : public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
+ boost::random_access_traversal_tag> {
+public:
+ iter_wrapper() = default;
+ explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
+
+ // Templated copy-constructor to allow for interoperable iterator and
+ // const_iterator.
+ template<class, class> friend class iter_wrapper;
+
+ template<class OtherIter, class OtherValue>
+ iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
+ typename std::enable_if<std::is_convertible<
+ OtherIter, WrappedIter>::value>::type * = nullptr)
+ : it(std::move(other.it)) {}
+
+ WrappedIter get() const { return it; }
+
+private:
+ friend class boost::iterator_core_access;
+
+ WrappedIter it;
+
+ void increment() { ++it; }
+ void decrement() { --it; }
+ void advance(size_t n) { it += n; }
+ typename std::iterator_traits<WrappedIter>::difference_type
+ distance_to(const iter_wrapper &other) const {
+ return other.it - it;
+ }
+ bool equal(const iter_wrapper &other) const { return it == other.it; }
+ Value &dereference() const { return *it; }
+};
+
+template<class Key, class Element>
+class element_store {
+ std::vector<Element> data;
+ ue2_unordered_map<Key, size_t> map;
+
+public:
+ bool empty() const {
+ return data.empty();
+ }
+
+ size_t size() const {
+ assert(data.size() == map.size());
+ return data.size();
+ }
+
+ void clear() {
+ data.clear();
+ map.clear();
+ }
+
+ void reserve(size_t n) {
+ data.reserve(n);
+ map.reserve(n);
+ }
+
+ // Iteration.
+
+ using const_iterator =
+ iter_wrapper<typename std::vector<Element>::const_iterator,
+ const Element>;
+ using iterator =
+ iter_wrapper<typename std::vector<Element>::iterator, Element>;
+
+ const_iterator begin() const {
+ return const_iterator(data.begin());
+ }
+
+ const_iterator end() const {
+ return const_iterator(data.end());
+ }
+
+ iterator begin() {
+ return iterator(data.begin());
+ }
+
+ iterator end() {
+ return iterator(data.end());
+ }
+
+ // Search.
+
+ const_iterator find(const Key &key) const {
+ auto map_it = map.find(key);
+ if (map_it == map.end()) {
+ return end();
+ }
+ auto idx = map_it->second;
+ assert(idx < data.size());
+ return begin() + idx;
+ }
+
+ iterator find(const Key &key) {
+ auto map_it = map.find(key);
+ if (map_it == map.end()) {
+ return end();
+ }
+ auto idx = map_it->second;
+ assert(idx < data.size());
+ return begin() + idx;
+ }
+
+ // Insert.
+
+ std::pair<iterator, bool> insert(const Key &key, const Element &element) {
+ const auto idx = data.size();
+ if (map.emplace(key, idx).second) {
+ data.push_back(element);
+ return {begin() + idx, true};
+ }
+ return {end(), false};
+ }
+
+ bool operator==(const element_store &a) const {
+ return data == a.data;
+ }
+
+ bool operator<(const element_store &a) const {
+ return data < a.data;
+ }
+
+ void swap(element_store &a) {
+ using std::swap;
+ swap(data, a.data);
+ swap(map, a.map);
+ }
+};
+
+} // namespace insertion_ordered_detail
+
+template<class Key, class Value>
+class insertion_ordered_map
+ : public totally_ordered<insertion_ordered_map<Key, Value>> {
+public:
+ using key_type = Key;
+ using mapped_type = Value;
+ using value_type = std::pair<const Key, Value>;
+
+private:
+ using store_type = insertion_ordered_detail::element_store<Key, value_type>;
+ store_type store;
+
+public:
+ using const_iterator = typename store_type::const_iterator;
+ using iterator = typename store_type::iterator;
+
+ insertion_ordered_map() = default;
+
+ template<class Iter>
+ insertion_ordered_map(Iter it, Iter it_end) {
+ insert(it, it_end);
+ }
+
+ explicit insertion_ordered_map(std::initializer_list<value_type> init) {
+ insert(init.begin(), init.end());
+ }
+
+ const_iterator begin() const { return store.begin(); }
+ const_iterator end() const { return store.end(); }
+ iterator begin() { return store.begin(); }
+ iterator end() { return store.end(); }
+
+ const_iterator find(const Key &key) const {
+ return store.find(key);
+ }
+
+ iterator find(const Key &key) {
+ return store.find(key);
+ }
+
+ std::pair<iterator, bool> insert(const std::pair<const Key, Value> &p) {
+ return store.insert(p.first, p);
+ }
+
+ template<class Iter>
+ void insert(Iter it, Iter it_end) {
+ for (; it != it_end; ++it) {
+ insert(*it);
+ }
+ }
+
+ Value &operator[](const Key &key) {
+ auto it = find(key);
+ if (it == end()) {
+ it = insert({key, Value{}}).first;
+ }
+ return it->second;
+ }
+
+ const Value &at(const Key &key) const {
+ return find(key)->second;
+ }
+
+ Value &at(const Key &key) {
+ return find(key)->second;
+ }
+
+ bool empty() const {
+ return store.empty();
+ }
+
+ size_t size() const {
+ return store.size();
+ }
+
+ void clear() {
+ store.clear();
+ }
+
+ void reserve(size_t n) {
+ store.reserve(n);
+ }
+
+ bool operator==(const insertion_ordered_map &a) const {
+ return store == a.store;
+ }
+
+ bool operator<(const insertion_ordered_map &a) const {
+ return store < a.store;
+ }
+
+ void swap(insertion_ordered_map &a) {
+ store.swap(a.store);
+ }
+
+ friend void swap(insertion_ordered_map &a, insertion_ordered_map &b) {
+ a.swap(b);
+ }
+};
+
+template<class Key>
+class insertion_ordered_set
+ : public totally_ordered<insertion_ordered_set<Key>> {
+public:
+ using key_type = Key;
+ using value_type = Key;
+
+private:
+ using store_type = insertion_ordered_detail::element_store<Key, value_type>;
+ store_type store;
+
+public:
+ using const_iterator = typename store_type::const_iterator;
+ using iterator = typename store_type::iterator;
+
+ insertion_ordered_set() = default;
+
+ template<class Iter>
+ insertion_ordered_set(Iter it, Iter it_end) {
+ insert(it, it_end);
+ }
+
+ explicit insertion_ordered_set(std::initializer_list<value_type> init) {
+ insert(init.begin(), init.end());
+ }
+
+ const_iterator begin() const { return store.begin(); }
+ const_iterator end() const { return store.end(); }
+
+ const_iterator find(const Key &key) const {
+ return store.find(key);
+ }
+
+ std::pair<iterator, bool> insert(const Key &key) {
+ return store.insert(key, key);
+ }
+
+ template<class Iter>
+ void insert(Iter it, Iter it_end) {
+ for (; it != it_end; ++it) {
+ insert(*it);
+ }
+ }
+
+ bool empty() const {
+ return store.empty();
+ }
+
+ size_t size() const {
+ return store.size();
+ }
+
+ void clear() {
+ store.clear();
+ }
+
+ void reserve(size_t n) {
+ store.reserve(n);
+ }
+
+ bool operator==(const insertion_ordered_set &a) const {
+ return store == a.store;
+ }
+
+ bool operator<(const insertion_ordered_set &a) const {
+ return store < a.store;
+ }
+
+ void swap(insertion_ordered_set &a) {
+ store.swap(a.store);
+ }
+
+ friend void swap(insertion_ordered_set &a, insertion_ordered_set &b) {
+ a.swap(b);
+ }
+};
+
+} // namespace ue2
+
+#endif // UTIL_INSERTION_ORDERED_H
internal/flat_set.cpp
internal/flat_map.cpp
internal/graph.cpp
+ internal/insertion_ordered.cpp
internal/lbr.cpp
internal/limex_nfa.cpp
internal/masked_move.cpp
--- /dev/null
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "ue2common.h"
+#include "util/insertion_ordered.h"
+
+#include "gtest/gtest.h"
+
+using namespace std;
+using namespace ue2;
+
+template <class K, class V>
+std::ostream &operator<<(std::ostream &os,
+ const insertion_ordered_map<K, V> &m) {
+ os << "{";
+ for (auto it = begin(m); it != end(m); ++it) {
+ os << "{" << it->first << ", " << it->second << "}";
+ if (it != end(m)) {
+ os << ", ";
+ }
+ }
+ os << "}";
+ return os;
+}
+
+TEST(insertion_ordered_map, empty) {
+ insertion_ordered_map<u32, u32> m;
+ EXPECT_TRUE(m.empty());
+ EXPECT_TRUE(m.begin() == m.end());
+ EXPECT_EQ(0, m.size());
+
+ m.insert({10, 10});
+ EXPECT_FALSE(m.empty());
+ EXPECT_EQ(1, m.size());
+
+ m.clear();
+ EXPECT_TRUE(m.empty());
+ EXPECT_TRUE(m.begin() == m.end());
+ EXPECT_EQ(0, m.size());
+}
+
+TEST(insertion_ordered_map, insert) {
+ const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
+ {10, 5}, {99, 6}, {12, 7}};
+ insertion_ordered_map<u32, u32> m;
+ for (const auto &e : v) {
+ m.insert(e);
+ }
+
+ EXPECT_FALSE(m.empty());
+ EXPECT_EQ(v.size(), m.size());
+ vector<pair<u32, u32>> v2(m.begin(), m.end());
+ EXPECT_EQ(v, v2);
+}
+
+TEST(insertion_ordered_map, insert_iter) {
+ const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
+ {10, 5}, {99, 6}, {12, 7}};
+ insertion_ordered_map<u32, u32> m;
+ m.insert(v.begin(), v.end());
+
+ EXPECT_FALSE(m.empty());
+ EXPECT_EQ(v.size(), m.size());
+ vector<pair<u32, u32>> v2(m.begin(), m.end());
+ EXPECT_EQ(v, v2);
+}
+
+TEST(insertion_ordered_map, find_const) {
+ const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
+ {10, 5}, {99, 6}, {12, 7}};
+ const insertion_ordered_map<u32, u32> m(v.begin(), v.end());
+
+ for (const auto &e : v) {
+ auto it = m.find(e.first);
+ ASSERT_NE(m.end(), it);
+ EXPECT_EQ(e.first, it->first);
+ EXPECT_EQ(e.second, it->second);
+ }
+}
+
+TEST(insertion_ordered_map, find_mutable) {
+ const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
+ {10, 5}, {99, 6}, {12, 7}};
+ insertion_ordered_map<u32, u32> m(v.begin(), v.end());
+
+ for (const auto &e : v) {
+ auto it = m.find(e.first);
+ ASSERT_NE(m.end(), it);
+ EXPECT_EQ(e.first, it->first);
+ EXPECT_EQ(e.second, it->second);
+ auto &mut = it->second;
+ ++mut;
+ EXPECT_EQ(e.second + 1, m.at(e.first));
+ }
+}
+
+TEST(insertion_ordered_map, operator_brackets) {
+ insertion_ordered_map<u32, u32> m;
+
+ u32 val = 1000;
+ for (u32 i = 10; i > 0; i--) {
+ m[i] = val++;
+ }
+
+ EXPECT_EQ(10, m.size());
+
+ val = 1000;
+ auto it = m.begin();
+ for (u32 i = 10; i > 0; i--) {
+ ASSERT_NE(m.end(), it);
+ EXPECT_EQ(i, it->first);
+ EXPECT_EQ(val, it->second);
+ ++val;
+ ++it;
+ }
+
+ ASSERT_EQ(m.end(), it);
+}
+
+template <class K>
+std::ostream &operator<<(std::ostream &os, const insertion_ordered_set<K> &s) {
+ os << "{";
+ for (auto it = begin(s); it != end(s); ++it) {
+ os << *it;
+ if (it != end(s)) {
+ os << ", ";
+ }
+ }
+ os << "}";
+ return os;
+}
+
+TEST(insertion_ordered_set, empty) {
+ insertion_ordered_set<u32> m;
+ EXPECT_TRUE(m.empty());
+ EXPECT_TRUE(m.begin() == m.end());
+ EXPECT_EQ(0, m.size());
+
+ m.insert(10);
+ EXPECT_FALSE(m.empty());
+ EXPECT_EQ(1, m.size());
+
+ m.clear();
+ EXPECT_TRUE(m.empty());
+ EXPECT_TRUE(m.begin() == m.end());
+ EXPECT_EQ(0, m.size());
+}
+
+TEST(insertion_ordered_set, insert) {
+ const vector<u32> v = {7, 1, 3, 10, 99, 12};
+ insertion_ordered_set<u32> s;
+ for (const auto &e : v) {
+ s.insert(e);
+ }
+
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(v.size(), s.size());
+ vector<u32> v2(s.begin(), s.end());
+ EXPECT_EQ(v, v2);
+}
+
+TEST(insertion_ordered_set, insert_iter) {
+ const vector<u32> v = {7, 1, 3, 10, 99, 12};
+ insertion_ordered_set<u32> s;
+ s.insert(v.begin(), v.end());
+
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(v.size(), s.size());
+ vector<u32> v2(s.begin(), s.end());
+ EXPECT_EQ(v, v2);
+}
+
+TEST(insertion_ordered_set, find_const) {
+ const vector<u32> v = {7, 1, 3, 10, 99, 12};
+ const insertion_ordered_set<u32> s(v.begin(), v.end());
+
+ for (const auto &e : v) {
+ auto it = s.find(e);
+ ASSERT_NE(s.end(), it);
+ EXPECT_EQ(e, *it);
+ }
+}