Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 158 lines (127 sloc) 4.147 kb
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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
#include "vm/symboltable.hpp"
#include "vm/exception.hpp"

#include "builtin/array.hpp"
#include "builtin/exception.hpp"
#include "builtin/string.hpp"
#include "builtin/symbol.hpp"

namespace rubinius {

  SymbolTable::Kind SymbolTable::detect_kind(const char* str, int size) {
    const char one = str[0];

    // A constant begins with an uppercase letter.
    if(one >= 'A' && one <= 'Z') {
      // Make sure that the rest of it is only alphanumerics
      for(int i = 1; i < size; i++) {
        if((isalnum(str[i]) || str[i] == '_') == false)
          return SymbolTable::Normal;
      }
      return SymbolTable::Constant;
    }

    if(one == '@' && size > 1) {
      // A class variable begins with @@
      if(str[1] == '@') {
        if(size > 2) {
          return SymbolTable::CVar;
        } else {
          return SymbolTable::Normal;
        }
      }

      // An instance variable begins with @
      return SymbolTable::IVar;
    }

    // A system variable begins with __
    if(size > 2 && one == '_' && str[1] == '_') {
      return SymbolTable::System;
    }

    // Everything else is normal
    return SymbolTable::Normal;
  }

  SymbolTable::Kind SymbolTable::kind(STATE, const Symbol* sym) {
    return kinds[sym->index()];
  }

  size_t SymbolTable::add(std::string str) {
    strings.push_back(str);
    kinds.push_back(detect_kind(str.c_str(), str.size()));
    return strings.size() - 1;
  }

  Symbol* SymbolTable::lookup(STATE, const char* str) {
    Symbol* sym = lookup(str);
    if(!sym) {
      Exception::argument_error(state, "Cannot create a symbol from an empty string");
      return NULL;
    }

    return sym;
  }

  Symbol* SymbolTable::lookup(const char* str) {
    size_t sym;

    if(*str == 0) return NULL;

    hashval hash = String::hash_str(str);

    // Symbols can be looked up by multiple threads at the same time.
    // This is fast operation, so we protect this with a spinlock.
    {
      thread::SpinLock::LockGuard guard(lock_);
      SymbolMap::iterator entry = symbols.find(hash);
      if(entry == symbols.end()) {
        sym = add(std::string(str));
        SymbolIds v(1, sym);
        symbols[hash] = v;
      } else {
        SymbolIds& v = entry->second;
        for(SymbolIds::iterator i = v.begin(); i != v.end(); i++) {
          std::string& s = strings[*i];

          if(!strcmp(s.c_str(), str)) return Symbol::from_index(*i);
        }
        sym = add(std::string(str));
        v.push_back(sym);
      }
    }

    return Symbol::from_index(sym);
  }

  Symbol* SymbolTable::lookup(STATE, String* str) {
    if(str->nil_p()) {
      Exception::argument_error(state, "Cannot look up Symbol from nil");
      return NULL;
    }

    const char* bytes = str->c_str();

    for(size_t i = 0; i < str->size(); i++) {
      if(bytes[i] == 0) {
        Exception::argument_error(state,
            "cannot create a symbol from a string containing `\\0'");
        return NULL;
      }
    }

    return lookup(state, bytes);
  }

  String* SymbolTable::lookup_string(STATE, const Symbol* sym) {
    if(sym->nil_p()) {
      Exception::argument_error(state, "Cannot look up Symbol from nil");
      return NULL;
    }

    std::string& str = strings[sym->index()];
    return String::create(state, str.c_str());
  }

  const char* SymbolTable::lookup_cstring(STATE, const Symbol* sym) {
    if(sym->nil_p()) {
      Exception::argument_error(state, "Cannot look up Symbol from nil");
      return NULL;
    }

    std::string& str = strings[sym->index()];
    return str.c_str();
  }

  const char* SymbolTable::lookup_cstring(const Symbol* sym) {
    std::string& str = strings[sym->index()];
    return str.c_str();
  }

  size_t SymbolTable::size() {
    return strings.size();
  }

  Array* SymbolTable::all_as_array(STATE) {
    size_t idx = 0;
    Array* ary = Array::create(state, this->size());

    for(SymbolMap::iterator s = symbols.begin(); s != symbols.end(); s++) {
      for(SymbolIds::iterator i = s->second.begin(); i != s->second.end(); i++) {
        ary->set(state, idx++, (Object*)Symbol::from_index(state, *i));
      }
    }

    return ary;
  }
}
Something went wrong with that request. Please try again.