Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

159 lines (127 sloc) 4.147 kb
#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;
}
}
Jump to Line
Something went wrong with that request. Please try again.