| [661e7b0] | 1 | #include "Symbol.hpp"
 | 
|---|
 | 2 | 
 | 
|---|
 | 3 | #include <unordered_map>
 | 
|---|
 | 4 | 
 | 
|---|
 | 5 | // This class (and the member-like helpers) are the implementation details
 | 
|---|
 | 6 | // of the Symbol class. It is just does reference counting to share strings.
 | 
|---|
 | 7 | // It is designed for maintainablity, but also to optimize the copy cases.
 | 
|---|
 | 8 | class SymbolData {
 | 
|---|
 | 9 | public:
 | 
|---|
 | 10 |         std::string const value;
 | 
|---|
 | 11 |         // As long as we are using a pointer sized counter,
 | 
|---|
 | 12 |         // overflow should never be an issue.
 | 
|---|
 | 13 |         std::size_t refCount;
 | 
|---|
 | 14 | 
 | 
|---|
 | 15 |         SymbolData(std::string const & value, std::size_t refCount) :
 | 
|---|
 | 16 |                 value(value), refCount(refCount)
 | 
|---|
 | 17 |         {}
 | 
|---|
 | 18 | };
 | 
|---|
 | 19 | 
 | 
|---|
 | 20 | namespace {
 | 
|---|
 | 21 |         template<typename T>
 | 
|---|
 | 22 |         struct IndirectHash {
 | 
|---|
 | 23 |                 std::hash<T> hasher;
 | 
|---|
 | 24 |                 std::size_t operator()(T const * const & val) const {
 | 
|---|
 | 25 |                         return hasher(*val);
 | 
|---|
 | 26 |                 }
 | 
|---|
 | 27 |         };
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 |         template<typename T>
 | 
|---|
 | 30 |         struct IndirectEqualTo {
 | 
|---|
 | 31 |                 std::equal_to<T> equals;
 | 
|---|
 | 32 |                 bool operator()(T const * const & lhs, T const * const & rhs) const {
 | 
|---|
 | 33 |                         return equals(*lhs, *rhs);
 | 
|---|
 | 34 |                 }
 | 
|---|
 | 35 |         };
 | 
|---|
 | 36 | } // namespace
 | 
|---|
 | 37 | 
 | 
|---|
 | 38 | using SymbolMap = std::unordered_map<std::string const *, SymbolData *,
 | 
|---|
 | 39 |         IndirectHash<std::string>, IndirectEqualTo<std::string>>;
 | 
|---|
 | 40 | 
 | 
|---|
 | 41 | /// Get the storage for the map of symbol data.
 | 
|---|
 | 42 | // Note: This is basically static memory, but wrapping the data in a function
 | 
|---|
 | 43 | // causes the constructor to run with the proper timing.
 | 
|---|
 | 44 | static SymbolMap & getAllSymbols() {
 | 
|---|
 | 45 |         static SymbolMap allSymbols;
 | 
|---|
 | 46 |         return allSymbols;
 | 
|---|
 | 47 | }
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | /// Clear out all unsed SymbolData.
 | 
|---|
 | 50 | static void eraseUnused() {
 | 
|---|
 | 51 |         SymbolMap & allSymbols = getAllSymbols();
 | 
|---|
 | 52 | 
 | 
|---|
 | 53 |         auto it = allSymbols.begin();
 | 
|---|
 | 54 |         while (it != allSymbols.end()) {
 | 
|---|
 | 55 |                 if (it->second->refCount) {
 | 
|---|
 | 56 |                         ++it;
 | 
|---|
 | 57 |                 } else {
 | 
|---|
 | 58 |                         delete it->second;
 | 
|---|
 | 59 |                         it = allSymbols.erase(it);
 | 
|---|
 | 60 |                 }
 | 
|---|
 | 61 |         }
 | 
|---|
 | 62 | }
 | 
|---|
 | 63 | 
 | 
|---|
 | 64 | /// Convert a string to a new or existing SymbolData.
 | 
|---|
 | 65 | static SymbolData * getSymbolData(std::string const & str) {
 | 
|---|
 | 66 |         SymbolMap & allSymbols = getAllSymbols();
 | 
|---|
 | 67 | 
 | 
|---|
 | 68 |         // If there is an existing symbol, re-use it.
 | 
|---|
 | 69 |         auto it = allSymbols.find(&str);
 | 
|---|
 | 70 |         if (it != allSymbols.end()) {
 | 
|---|
 | 71 |                 SymbolData * data = it->second;
 | 
|---|
 | 72 |                 ++data->refCount;
 | 
|---|
 | 73 |                 return data;
 | 
|---|
 | 74 |         }
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 |         // If these is no existing symbol, create the required data.
 | 
|---|
 | 77 |         SymbolData * data = new SymbolData(str, 1);
 | 
|---|
 | 78 |         allSymbols.insert(std::make_pair(&data->value, data));
 | 
|---|
 | 79 |         return data;
 | 
|---|
 | 80 | }
 | 
|---|
 | 81 | 
 | 
|---|
 | 82 | /// Reduce reference count and free the SymbolData as needed.
 | 
|---|
 | 83 | static void decSymbolData(SymbolData * data) {
 | 
|---|
 | 84 |         // First comes the actual decrement.
 | 
|---|
 | 85 |         --data->refCount;
 | 
|---|
 | 86 | 
 | 
|---|
 | 87 |         // If it has hit zero, remove it from the map.
 | 
|---|
 | 88 |         if (0 == data->refCount) {
 | 
|---|
 | 89 |                 eraseUnused();
 | 
|---|
 | 90 |         }
 | 
|---|
 | 91 | }
 | 
|---|
 | 92 | 
 | 
|---|
 | 93 | Symbol::Symbol() : data(getSymbolData(std::string())) {}
 | 
|---|
 | 94 | 
 | 
|---|
 | 95 | Symbol::Symbol(std::string const & str) : data(getSymbolData(str)) {}
 | 
|---|
 | 96 | 
 | 
|---|
 | 97 | Symbol::Symbol(char const * str) : data(getSymbolData(str)) {}
 | 
|---|
 | 98 | 
 | 
|---|
 | 99 | Symbol::Symbol(Symbol const & other) : data(other.data) {
 | 
|---|
 | 100 |         ++data->refCount;
 | 
|---|
 | 101 | }
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 | Symbol::Symbol(Symbol && other) : data(other.data) {
 | 
|---|
 | 104 |         ++data->refCount;
 | 
|---|
 | 105 | }
 | 
|---|
 | 106 | 
 | 
|---|
 | 107 | Symbol::~Symbol() {
 | 
|---|
 | 108 |         decSymbolData(data);
 | 
|---|
 | 109 | }
 | 
|---|
 | 110 | 
 | 
|---|
 | 111 | Symbol & Symbol::operator=(std::string const & str) {
 | 
|---|
 | 112 |         SymbolData * dat = getSymbolData(str);
 | 
|---|
 | 113 |         decSymbolData(data);
 | 
|---|
 | 114 |         data = dat;
 | 
|---|
 | 115 |         return *this;
 | 
|---|
 | 116 | }
 | 
|---|
 | 117 | 
 | 
|---|
 | 118 | Symbol & Symbol::operator=(char const * str) {
 | 
|---|
 | 119 |         return this->operator=(std::string(str));
 | 
|---|
 | 120 | }
 | 
|---|
 | 121 | 
 | 
|---|
 | 122 | Symbol & Symbol::operator=(Symbol const & other) {
 | 
|---|
 | 123 |         ++other.data->refCount;
 | 
|---|
 | 124 |         decSymbolData(data);
 | 
|---|
 | 125 |         data = other.data;
 | 
|---|
 | 126 |         return *this;
 | 
|---|
 | 127 | }
 | 
|---|
 | 128 | 
 | 
|---|
 | 129 | Symbol & Symbol::operator=(Symbol && other) {
 | 
|---|
 | 130 |         Symbol const & ref = other;
 | 
|---|
 | 131 |         return this->operator=(ref);
 | 
|---|
 | 132 | }
 | 
|---|
 | 133 | 
 | 
|---|
 | 134 | bool Symbol::operator==(Symbol const & other) const {
 | 
|---|
 | 135 |         return data == other.data;
 | 
|---|
 | 136 | }
 | 
|---|
 | 137 | 
 | 
|---|
 | 138 | bool Symbol::operator!=(Symbol const & other) const {
 | 
|---|
 | 139 |         return data != other.data;
 | 
|---|
 | 140 | }
 | 
|---|
 | 141 | 
 | 
|---|
 | 142 | std::string const & Symbol::str() const {
 | 
|---|
 | 143 |         return data->value;
 | 
|---|
 | 144 | }
 | 
|---|
 | 145 | 
 | 
|---|
 | 146 | char const * Symbol::c_str() const {
 | 
|---|
 | 147 |         return data->value.c_str();
 | 
|---|
 | 148 | }
 | 
|---|