/*++ Copyright (c) 2006 Microsoft Corporation Module Name: symbol.h Abstract: Lisp-like symbols. Author: Leonardo de Moura (leonardo) 2006-09-11. Revision History: --*/ #pragma once #include #include #include #include "util/util.h" #include "util/tptr.h" #include "util/string_buffer.h" template class symbol_table; class symbol { char const * m_data; template friend class symbol_table; explicit symbol(void const * data): m_data(reinterpret_cast(data)) { } bool is_marked() const { return GET_TAG(m_data) > 1; } static symbol mark(symbol s) { SASSERT(!s.is_marked()); return symbol(TAG(void *, UNTAG(void *, s.m_data), GET_TAG(s.m_data) + 2)); } static symbol unmark(symbol s) { SASSERT(s.is_marked()); return symbol(TAG(void *, UNTAG(void *, s.m_data), GET_TAG(s.m_data) - 2)); } static symbol m_dummy; public: symbol(): m_data(nullptr) { } explicit symbol(char const * d); explicit symbol(const std::string & str) : symbol(str.c_str()) {} explicit symbol(unsigned idx): m_data(BOXTAGINT(char const *, idx, 1)) { #if !defined(__LP64__) && !defined(_WIN64) SASSERT(idx < (SIZE_MAX >> PTR_ALIGNMENT)); #endif } static symbol dummy() { return m_dummy; } static const symbol null; symbol & operator=(char const * d); friend bool operator==(symbol const & s1, symbol const & s2) { return s1.m_data == s2.m_data; } friend bool operator!=(symbol const & s1, symbol const & s2) { return s1.m_data != s2.m_data; } bool is_numerical() const { return GET_TAG(m_data) == 1; } bool is_null() const { return m_data == nullptr; } bool is_non_empty_string() const { return !is_null() && !is_numerical() && 0 != bare_str()[0]; } unsigned int get_num() const { SASSERT(is_numerical()); return UNBOXINT(m_data); } std::string str() const; friend bool operator==(symbol const & s1, char const * s2) { if (s1.m_data == nullptr && s2 == nullptr) return true; if (s1.m_data == nullptr || s2 == nullptr) return false; if (!s1.is_numerical()) return strcmp(s1.bare_str(), s2) == 0; return s1.str() == s2; } friend bool operator!=(symbol const & s1, char const * s2) { return !operator==(s1, s2); } // C-API only functions void * c_api_symbol2ext() const { return const_cast(m_data); } static symbol c_api_ext2symbol(void const * ptr) { return symbol(ptr); } unsigned hash() const { if (m_data == nullptr) return 0x9e3779d9; else if (is_numerical()) return get_num(); else return static_cast(reinterpret_cast(m_data)[-1]); } bool contains(char c) const; unsigned display_size() const; char const * bare_str() const { SASSERT(!is_numerical()); return m_data; } friend std::ostream & operator<<(std::ostream & target, symbol s) { SASSERT(!s.is_marked()); if (GET_TAG(s.m_data) == 0) { if (s.m_data) { target << s.m_data; } else { target << "null"; } } else { target << "k!" << UNBOXINT(s.m_data); } return target; } template friend string_buffer & operator<<(string_buffer & target, symbol s) { SASSERT(!s.is_marked()); if (GET_TAG(s.m_data) == 0) { if (s.m_data) { target << s.m_data; } else { target << "null"; } } else { target << "k!" << UNBOXINT(s.m_data); } return target; } }; struct symbol_hash_proc { unsigned operator()(symbol const & s) const { return s.hash(); } }; struct symbol_eq_proc { bool operator()(symbol const & s1, symbol const & s2) const { return s1 == s2; } }; void initialize_symbols(); void finalize_symbols(); /* ADD_INITIALIZER('initialize_symbols();') ADD_FINALIZER('finalize_symbols();') */ // total order on symbols... I did not overloaded '<' to avoid misunderstandings. // numerical symbols are smaller than non numerical symbols. // two numerical symbols are compared using get_num. // two non-numerical symbols are compared using string comparison. bool lt(symbol const & s1, symbol const & s2);