#ifndef HALIDE_SCOPE_H
#define HALIDE_SCOPE_H
#include <string>
#include <map>
#include <stack>
#include <utility>
#include <iostream>
#include "Util.h"
#include "Debug.h"
#include "Error.h"
namespace Halide {
namespace Internal {
template<typename T>
class SmallStack {
private:
T _top;
std::vector<T> _rest;
bool _empty;
public:
SmallStack() : _empty(true) {}
void pop() {
if (_rest.empty()) {
_empty = true;
_top = T();
} else {
_top = _rest.back();
_rest.pop_back();
}
}
void push(const T &t) {
if (_empty) {
_empty = false;
} else {
_rest.push_back(_top);
}
_top = t;
}
T top() const {
return _top;
}
T &top_ref() {
return _top;
}
const T &top_ref() const {
return _top;
}
bool empty() const {
return _empty;
}
};
template<typename T>
class Scope {
private:
std::map<std::string, SmallStack<T>> table;
Scope(const Scope<T> &);
Scope<T> &operator=(const Scope<T> &);
const Scope<T> *containing_scope;
public:
Scope() : containing_scope(nullptr) {}
void set_containing_scope(const Scope<T> *s) {
containing_scope = s;
}
static const Scope<T> &empty_scope() {
static Scope<T> *_empty_scope = new Scope<T>();
return *_empty_scope;
}
T get(const std::string &name) const {
typename std::map<std::string, SmallStack<T>>::const_iterator iter = table.find(name);
if (iter == table.end() || iter->second.empty()) {
if (containing_scope) {
return containing_scope->get(name);
} else {
internal_error << "Symbol '" << name << "' not found\n";
}
}
return iter->second.top();
}
T &ref(const std::string &name) {
typename std::map<std::string, SmallStack<T>>::iterator iter = table.find(name);
if (iter == table.end() || iter->second.empty()) {
internal_error << "Symbol '" << name << "' not found\n";
}
return iter->second.top_ref();
}
bool contains(const std::string &name) const {
typename std::map<std::string, SmallStack<T>>::const_iterator iter = table.find(name);
if (iter == table.end() || iter->second.empty()) {
if (containing_scope) {
return containing_scope->contains(name);
} else {
return false;
}
}
return true;
}
void push(const std::string &name, const T &value) {
table[name].push(value);
}
void pop(const std::string &name) {
typename std::map<std::string, SmallStack<T>>::iterator iter = table.find(name);
internal_assert(iter != table.end()) << "Name not in symbol table: " << name << "\n";
iter->second.pop();
if (iter->second.empty()) {
table.erase(iter);
}
}
class const_iterator {
typename std::map<std::string, SmallStack<T>>::const_iterator iter;
public:
explicit const_iterator(const typename std::map<std::string, SmallStack<T>>::const_iterator &i) :
iter(i) {
}
const_iterator() {}
bool operator!=(const const_iterator &other) {
return iter != other.iter;
}
void operator++() {
++iter;
}
const std::string &name() {
return iter->first;
}
const SmallStack<T> &stack() {
return iter->second;
}
const T &value() {
return iter->second.top_ref();
}
};
const_iterator cbegin() const {
return const_iterator(table.begin());
}
const_iterator cend() const {
return const_iterator(table.end());
}
class iterator {
typename std::map<std::string, SmallStack<T>>::iterator iter;
public:
explicit iterator(typename std::map<std::string, SmallStack<T>>::iterator i) :
iter(i) {
}
iterator() {}
bool operator!=(const iterator &other) {
return iter != other.iter;
}
void operator++() {
++iter;
}
const std::string &name() {
return iter->first;
}
SmallStack<T> &stack() {
return iter->second;
}
T &value() {
return iter->second.top_ref();
}
};
iterator begin() {
return iterator(table.begin());
}
iterator end() {
return iterator(table.end());
}
void swap(Scope<T> &other) {
table.swap(other.table);
std::swap(containing_scope, other.containing_scope);
}
};
template<typename T>
std::ostream &operator<<(std::ostream &stream, const Scope<T>& s) {
stream << "{\n";
typename Scope<T>::const_iterator iter;
for (iter = s.cbegin(); iter != s.cend(); ++iter) {
stream << " " << iter.name() << "\n";
}
stream << "}";
return stream;
}
}
}
#endif