File: NameMap.h

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (107 lines) | stat: -rw-r--r-- 2,637 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once
#include "CppName.h"
#include "SrcPos.h"
#include "Auto.h"
#include "Exception.h"

/**
 * A map from C++ names into some type. Acts like both a searchable map as well as an ordered array.
 *
 * Assumes T::name, T::pos and T::id exists. Auto<T> has to be usable.
 */
template <class T>
class NameMap {
public:
	NameMap(const vector<CppName> &usingExpr, const map<CppName, CppName> *aliases = null) :
		usingExpr(usingExpr), aliases(aliases) {}

	// Insert a new element at the end.
	void insert(const Auto<T> &v) {
		if (lookup.count(v->name))
			throw Error(L"The name " + toS(v->name) + L" is defined twice!", v->pos);

		lookup.insert(make_pair(v->name, nat(order.size())));
		order.push_back(v);
	}

	// Order the types according to a predicate.
	template <class Pred>
	void sort(const Pred &pred) {
		std::sort(order.begin(), order.end(), pred);

		for (nat i = 0; i < order.size(); i++) {
			order[i]->id = i;
			lookup[order[i]->name] = i;
		}
	}

	// Total number of elements.
	nat size() const {
		return nat(order.size());
	}

	// Access elements.
	const Auto<T> &operator[] (nat id) const {
		return order[id];
	}

	// Find by name.
	T *findUnsafe(const CppName &name, CppName context) const {
		map<CppName, nat>::const_iterator i = lookup.find(name);
		if (i != lookup.end())
			return order[i->second].borrow();

		while (!context.empty()) {
			CppName candidate = context + name;

			if (aliases) {
				map<CppName, CppName>::const_iterator j = aliases->find(candidate);
				if (j != aliases->end()) {
					i = lookup.find(j->second);
					if (i == lookup.end())
						throw Error(L"The target " + j->second + L" for alias " + j->first + L" was not found. "
									L"Note that aliases must specify the full name of the type!", SrcPos());
					return order[i->second].borrow();
				}
			}

			i = lookup.find(candidate);
			if (i != lookup.end())
				return order[i->second].borrow();

			context = context.parent();
		}

		// Reachable via 'using namespace'?
		for (nat j = 0; j < usingExpr.size(); j++) {
			i = lookup.find(usingExpr[j] + name);
			if (i != lookup.end())
				return order[i->second].borrow();
		}

		return null;
	}

	// Find by name, throws exception if not found.
	T *find(const CppName &name, CppName context, const SrcPos &pos) const {
		T *t = findUnsafe(name, context);
		if (!t)
			throw Error(L"The name " + name + L" is not known to Storm.", pos);
		return t;
	}


private:
	// All using-expressions.
	const vector<CppName> &usingExpr;

	// Type aliases.
	const map<CppName, CppName> *aliases;

	// Quick lookups.
	map<CppName, nat> lookup;

	// Order.
	vector<Auto<T>> order;
};