| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // -*- mode: C++ -*- |
| // |
| // Copyright (C) 2013-2020 Red Hat, Inc. |
| |
| /// @file |
| |
| #include <functional> |
| #include "abg-internal.h" |
| // <headers defining libabigail's API go under here> |
| ABG_BEGIN_EXPORT_DECLARATIONS |
| |
| #include "abg-hash.h" |
| #include "abg-ir.h" |
| |
| ABG_END_EXPORT_DECLARATIONS |
| // </headers defining libabigail's API> |
| |
| namespace abigail |
| { |
| |
| namespace hashing |
| { |
| |
| // Mix 3 32 bits values reversibly. Borrowed from hashtab.c in gcc tree. |
| #define abigail_hash_mix(a, b, c) \ |
| { \ |
| a -= b; a -= c; a ^= (c>>13); \ |
| b -= c; b -= a; b ^= (a<< 8); \ |
| c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ |
| a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ |
| b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ |
| c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ |
| a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ |
| b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ |
| c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ |
| } |
| |
| size_t |
| combine_hashes(size_t val1, size_t val2) |
| { |
| /* the golden ratio; an arbitrary value. */ |
| size_t a = 0x9e3779b9; |
| abigail_hash_mix(a, val1, val2); |
| return val2; |
| } |
| |
| /// Compute a stable string hash. |
| /// |
| /// std::hash has no portability or stability guarantees so is |
| /// unsuitable where reproducibility is a requirement such as in XML |
| /// output. |
| /// |
| /// This is the 32-bit FNV-1a algorithm. The algorithm, reference code |
| /// and constants are all unencumbered. It is fast and has reasonable |
| /// distribution properties. |
| /// |
| /// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function |
| /// |
| /// @param str the string to hash. |
| /// |
| /// @return an unsigned 32 bit hash value. |
| uint32_t |
| fnv_hash(const std::string& str) |
| { |
| const uint32_t prime = 0x01000193; |
| const uint32_t offset_basis = 0x811c9dc5; |
| uint32_t hash = offset_basis; |
| for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) |
| { |
| uint8_t byte = *i; |
| hash = hash ^ byte; |
| hash = hash * prime; |
| } |
| return hash; |
| } |
| |
| }//end namespace hashing |
| |
| using std::list; |
| using std::vector; |
| |
| using namespace abigail::ir; |
| |
| // See forward declarations in abg-ir.h. |
| |
| // Definitions. |
| |
| /// Hash function for an instance of @ref type_base. |
| /// |
| /// @param t the type to hash. |
| /// |
| /// @return the type value. |
| size_t |
| type_base::hash::operator()(const type_base& t) const |
| { |
| std::hash<size_t> size_t_hash; |
| std::hash<string> str_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, size_t_hash(t.get_size_in_bits())); |
| v = hashing::combine_hashes(v, size_t_hash(t.get_alignment_in_bits())); |
| |
| return v; |
| } |
| |
| /// Hash function for an instance of @ref type_base. |
| /// |
| /// @param t the type to hash. |
| /// |
| /// @return the type value. |
| size_t |
| type_base::hash::operator()(const type_base* t) const |
| {return operator()(*t);} |
| |
| /// Hash function for an instance of @ref type_base. |
| /// |
| /// @param t the type to hash. |
| /// |
| /// @return the type value. |
| size_t |
| type_base::hash::operator()(const type_base_sptr t) const |
| {return operator()(*t);} |
| |
| struct decl_base::hash |
| { |
| size_t |
| operator()(const decl_base& d) const |
| { |
| std::hash<string> str_hash; |
| |
| size_t v = str_hash(typeid(d).name()); |
| if (!d.get_linkage_name().empty()) |
| v = hashing::combine_hashes(v, str_hash(d.get_linkage_name())); |
| if (!d.get_name().empty()) |
| v = hashing::combine_hashes(v, str_hash(d.get_qualified_name())); |
| if (is_member_decl(d)) |
| { |
| v = hashing::combine_hashes(v, get_member_access_specifier(d)); |
| v = hashing::combine_hashes(v, get_member_is_static(d)); |
| } |
| return v; |
| } |
| }; // end struct decl_base::hash |
| |
| struct type_decl::hash |
| { |
| size_t |
| operator()(const type_decl& t) const |
| { |
| decl_base::hash decl_hash; |
| type_base::hash type_hash; |
| std::hash<string> str_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, type_hash(t)); |
| |
| return v; |
| } |
| }; |
| |
| /// Hashing operator for the @ref scope_decl type. |
| /// |
| /// @param d the scope_decl to hash. |
| /// |
| /// @return the hash value. |
| size_t |
| scope_decl::hash::operator()(const scope_decl& d) const |
| { |
| std::hash<string> hash_string; |
| size_t v = hash_string(typeid(d).name()); |
| for (scope_decl::declarations::const_iterator i = |
| d.get_member_decls().begin(); |
| i != d.get_member_decls().end(); |
| ++i) |
| v = hashing::combine_hashes(v, (*i)->get_hash()); |
| |
| return v; |
| } |
| |
| /// Hashing operator for the @ref scope_decl type. |
| /// |
| /// @param d the scope_decl to hash. |
| /// |
| /// @return the hash value. |
| size_t |
| scope_decl::hash::operator()(const scope_decl* d) const |
| {return d? operator()(*d) : 0;} |
| |
| struct scope_type_decl::hash |
| { |
| size_t |
| operator()(const scope_type_decl& t) const |
| { |
| decl_base::hash decl_hash; |
| type_base::hash type_hash; |
| std::hash<string> str_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, type_hash(t)); |
| |
| return v; |
| } |
| }; |
| |
| struct qualified_type_def::hash |
| { |
| size_t |
| operator()(const qualified_type_def& t) const |
| { |
| type_base::hash type_hash; |
| decl_base::hash decl_hash; |
| std::hash<string> str_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, type_hash(t)); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, t.get_cv_quals()); |
| return v; |
| } |
| }; |
| |
| struct pointer_type_def::hash |
| { |
| size_t |
| operator()(const pointer_type_def& t) const |
| { |
| std::hash<string> str_hash; |
| type_base::hash type_base_hash; |
| decl_base::hash decl_hash; |
| type_base::shared_ptr_hash hash_type_ptr; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, type_base_hash(t)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_pointed_to_type())); |
| return v ; |
| } |
| }; |
| |
| struct reference_type_def::hash |
| { |
| size_t |
| operator()(const reference_type_def& t) |
| { |
| std::hash<string> hash_str; |
| type_base::hash hash_type_base; |
| decl_base::hash hash_decl; |
| type_base::shared_ptr_hash hash_type_ptr; |
| |
| size_t v = hash_str(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_str(t.is_lvalue() |
| ? "lvalue" |
| : "rvalue")); |
| v = hashing::combine_hashes(v, hash_type_base(t)); |
| v = hashing::combine_hashes(v, hash_decl(t)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_pointed_to_type())); |
| return v; |
| } |
| }; |
| |
| struct array_type_def::subrange_type::hash |
| { |
| size_t |
| operator()(const array_type_def::subrange_type& s) const |
| { |
| std::hash<int> hash_size_t; |
| size_t v = hash_size_t(hash_size_t(s.get_lower_bound())); |
| v = hashing::combine_hashes(v, hash_size_t(s.get_upper_bound())); |
| return v; |
| } |
| }; |
| |
| struct array_type_def::hash |
| { |
| size_t |
| operator()(const array_type_def& t) |
| { |
| std::hash<string> hash_str; |
| type_base::hash hash_type_base; |
| decl_base::hash hash_decl; |
| type_base::shared_ptr_hash hash_type_ptr; |
| array_type_def::subrange_type::hash hash_subrange; |
| |
| size_t v = hash_str(typeid(t).name()); |
| |
| v = hashing::combine_hashes(v, hash_type_base(t)); |
| v = hashing::combine_hashes(v, hash_decl(t)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_element_type())); |
| |
| for (vector<array_type_def::subrange_sptr >::const_iterator i = |
| t.get_subranges().begin(); |
| i != t.get_subranges().end(); |
| ++i) |
| v = hashing::combine_hashes(v, hash_subrange(**i)); |
| |
| return v; |
| } |
| }; |
| |
| struct enum_type_decl::hash |
| { |
| size_t |
| operator()(const enum_type_decl& t) const |
| { |
| std::hash<string> str_hash; |
| decl_base::hash decl_hash; |
| type_base::shared_ptr_hash type_ptr_hash; |
| std::hash<size_t> size_t_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, type_ptr_hash(t.get_underlying_type())); |
| for (enum_type_decl::enumerators::const_iterator i = |
| t.get_enumerators().begin(); |
| i != t.get_enumerators().end(); |
| ++i) |
| { |
| v = hashing::combine_hashes(v, str_hash(i->get_name())); |
| v = hashing::combine_hashes(v, size_t_hash(i->get_value())); |
| } |
| return v; |
| } |
| }; |
| |
| struct typedef_decl::hash |
| { |
| size_t |
| operator()(const typedef_decl& t) const |
| { |
| std::hash<string> str_hash; |
| type_base::hash hash_type; |
| decl_base::hash decl_hash; |
| type_base::shared_ptr_hash type_ptr_hash; |
| |
| size_t v = str_hash(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_type(t)); |
| v = hashing::combine_hashes(v, decl_hash(t)); |
| v = hashing::combine_hashes(v, type_ptr_hash(t.get_underlying_type())); |
| return v; |
| } |
| }; |
| |
| /// Compute a hash for an instance @ref var_decl. |
| /// |
| /// Note that this function caches the hashing value the |
| /// decl_base::hash_ data member of the input instance and re-uses it |
| /// when it is already calculated. |
| /// |
| /// @param t the instance of @ref var_decl to compute the hash for. |
| /// |
| /// @return the calculated hash value, or the one that was previously |
| /// calculated. |
| size_t |
| var_decl::hash::operator()(const var_decl& t) const |
| { |
| std::hash<string> hash_string; |
| decl_base::hash hash_decl; |
| type_base::shared_ptr_hash hash_type_ptr; |
| std::hash<size_t> hash_size_t; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_decl(t)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_type())); |
| |
| if (is_data_member(t) && get_data_member_is_laid_out(t)) |
| { |
| v = hashing::combine_hashes(v, hash_decl(*t.get_scope())); |
| v = hashing::combine_hashes(v, hash_size_t(get_data_member_offset(t))); |
| } |
| |
| return v; |
| } |
| |
| /// Compute a hash for a pointer to @ref var_decl. |
| /// |
| /// @param t the pointer to @ref var_decl to compute the hash for. |
| /// |
| /// @return the calculated hash value |
| size_t |
| var_decl::hash::operator()(const var_decl* t) const |
| {return operator()(*t);} |
| |
| /// Compute a hash value for an instance of @ref function_decl. |
| /// |
| /// Note that this function caches the resulting hash in the |
| /// decl_base::hash_ data member of the instance of @ref |
| /// function_decl, and just returns if it is already calculated. |
| /// |
| /// @param t the function to calculate the hash for. |
| /// |
| /// @return the hash value. |
| size_t |
| function_decl::hash::operator()(const function_decl& t) const |
| { |
| std::hash<int> hash_int; |
| std::hash<size_t> hash_size_t; |
| std::hash<bool> hash_bool; |
| std::hash<string> hash_string; |
| decl_base::hash hash_decl_base; |
| type_base::shared_ptr_hash hash_type_ptr; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_decl_base(t)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_type())); |
| v = hashing::combine_hashes(v, hash_bool(t.is_declared_inline())); |
| v = hashing::combine_hashes(v, hash_int(t.get_binding())); |
| if (is_member_function(t)) |
| { |
| bool is_ctor = get_member_function_is_ctor(t), |
| is_dtor = get_member_function_is_dtor(t), |
| is_static = get_member_is_static(t), |
| is_const = get_member_function_is_const(t); |
| size_t voffset = get_member_function_vtable_offset(t); |
| |
| v = hashing::combine_hashes(v, hash_bool(is_ctor)); |
| v = hashing::combine_hashes(v, hash_bool(is_dtor)); |
| v = hashing::combine_hashes(v, hash_bool(is_static)); |
| v = hashing::combine_hashes(v, hash_bool(is_const)); |
| if (!is_static && !is_ctor) |
| v = hashing::combine_hashes(v, hash_size_t(voffset)); |
| } |
| |
| return v; |
| } |
| |
| /// Compute a hash for a pointer to @ref function_decl. |
| /// |
| /// @param t the pointer to @ref function_decl to compute the hash for. |
| /// |
| /// @return the calculated hash value |
| size_t |
| function_decl::hash::operator()(const function_decl* t) const |
| {return operator()(*t);} |
| |
| size_t |
| function_decl::parameter::hash::operator() |
| (const function_decl::parameter& p) const |
| { |
| type_base::shared_ptr_hash hash_type_ptr; |
| std::hash<bool> hash_bool; |
| std::hash<unsigned> hash_unsigned; |
| size_t v = hash_type_ptr(p.get_type()); |
| v = hashing::combine_hashes(v, hash_unsigned(p.get_index())); |
| v = hashing::combine_hashes(v, hash_bool(p.get_variadic_marker())); |
| return v; |
| } |
| |
| size_t |
| function_decl::parameter::hash::operator() |
| (const function_decl::parameter* p) const |
| {return operator()(*p);} |
| |
| size_t |
| function_decl::parameter::hash::operator() |
| (const function_decl::parameter_sptr p) const |
| {return operator()(p.get());} |
| |
| /// Hashing functor for the @ref method_type type. |
| struct method_type::hash |
| { |
| size_t |
| operator()(const method_type& t) const |
| { |
| std::hash<string> hash_string; |
| type_base::shared_ptr_hash hash_type_ptr; |
| function_decl::parameter::hash hash_parameter; |
| |
| size_t v = hash_string(typeid(t).name()); |
| string class_name = t.get_class_type()->get_qualified_name(); |
| v = hashing::combine_hashes(v, hash_string(class_name)); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_return_type())); |
| vector<shared_ptr<function_decl::parameter> >::const_iterator i = |
| t.get_first_non_implicit_parm(); |
| |
| for (; i != t.get_parameters().end(); ++i) |
| v = hashing::combine_hashes(v, hash_parameter(**i)); |
| |
| return v; |
| } |
| |
| size_t |
| operator()(const method_type* t) |
| {return operator()(*t);} |
| |
| size_t |
| operator()(const method_type_sptr t) |
| {return operator()(t.get());} |
| }; // end struct method_type::hash |
| |
| // <struct function_type::hash stuff> |
| |
| /// Hashing function for @ref function_type. |
| /// |
| /// @param t the function type to hash. |
| /// |
| /// @return the resulting hash value. |
| size_t |
| function_type::hash::operator()(const function_type& t) const |
| { |
| std::hash<string> hash_string; |
| type_base::shared_ptr_hash hash_type_ptr; |
| function_decl::parameter::hash hash_parameter; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_return_type())); |
| for (vector<shared_ptr<function_decl::parameter> >::const_iterator i = |
| t.get_first_non_implicit_parm(); |
| i != t.get_parameters().end(); |
| ++i) |
| v = hashing::combine_hashes(v, hash_parameter(**i)); |
| return v; |
| } |
| |
| /// Hashing function for a pointer to @ref function_type. |
| /// |
| /// @param t the pointer to @ref function_type to hash. |
| /// |
| /// @return the resulting hash value. |
| size_t |
| function_type::hash::operator()(const function_type* t) const |
| { |
| if (const method_type* m = dynamic_cast<const method_type*>(t)) |
| { |
| method_type::hash h; |
| return h(m); |
| } |
| return operator()(*t); |
| } |
| |
| /// Hashing function for a shared pointer to @ref function_type. |
| /// |
| /// @param t the pointer to @ref function_type to hash. |
| /// |
| /// @return the resulting hash value. |
| size_t |
| function_type::hash::operator()(const function_type_sptr t) const |
| {return operator()(t.get());} |
| |
| // </struct function_type::hash stuff> |
| |
| size_t |
| member_base::hash::operator()(const member_base& m) const |
| { |
| std::hash<int> hash_int; |
| return hash_int(m.get_access_specifier()); |
| } |
| |
| size_t |
| class_decl::base_spec::hash::operator()(const base_spec& t) const |
| { |
| member_base::hash hash_member; |
| type_base::shared_ptr_hash hash_type_ptr; |
| std::hash<size_t> hash_size; |
| std::hash<bool> hash_bool; |
| std::hash<string> hash_string; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_member(t)); |
| v = hashing::combine_hashes(v, hash_size(t.get_offset_in_bits())); |
| v = hashing::combine_hashes(v, hash_bool(t.get_is_virtual())); |
| v = hashing::combine_hashes(v, hash_type_ptr(t.get_base_class())); |
| return v; |
| } |
| |
| size_t |
| member_function_template::hash::operator() |
| (const member_function_template& t) const |
| { |
| std::hash<bool> hash_bool; |
| function_tdecl::hash hash_function_tdecl; |
| member_base::hash hash_member; |
| std::hash<string> hash_string; |
| |
| size_t v = hash_member(t); |
| string n = t.get_qualified_name(); |
| v = hashing::combine_hashes(v, hash_string(n)); |
| v = hashing::combine_hashes(v, hash_function_tdecl(t)); |
| v = hashing::combine_hashes(v, hash_bool(t.is_constructor())); |
| v = hashing::combine_hashes(v, hash_bool(t.is_const())); |
| return v; |
| } |
| |
| size_t |
| member_class_template::hash::operator() |
| (const member_class_template& t) const |
| { |
| member_base::hash hash_member; |
| class_tdecl::hash hash_class_tdecl; |
| std::hash<string> hash_string; |
| |
| size_t v = hash_member(t); |
| string n = t.get_qualified_name(); |
| v = hashing::combine_hashes(v, hash_string(n)); |
| v = hashing::combine_hashes(v, hash_class_tdecl(t)); |
| return v; |
| } |
| |
| /// Compute a hash for a @ref class_or_union |
| /// |
| /// @param t the class_or_union for which to compute the hash value. |
| /// |
| /// @return the computed hash value. |
| size_t |
| class_or_union::hash::operator()(const class_or_union& t) const |
| { |
| if (t.hashing_started() |
| || (t.get_is_declaration_only() && !t.get_definition_of_declaration())) |
| // All non-resolved decl-only types have a hash of zero. Their hash |
| // will differ from the resolved hash, but then at least, having |
| // it be zero will give a hint that we couldn't actually compute |
| // the hash. |
| return 0; |
| |
| // If the type is decl-only and now has a definition, then hash its |
| // definition instead. |
| |
| if (t.get_is_declaration_only()) |
| { |
| ABG_ASSERT(t.get_definition_of_declaration()); |
| size_t v = operator() |
| (*is_class_or_union_type(t.get_definition_of_declaration())); |
| return v; |
| } |
| |
| ABG_ASSERT(!t.get_is_declaration_only()); |
| |
| std::hash<string> hash_string; |
| scope_type_decl::hash hash_scope_type; |
| var_decl::hash hash_data_member; |
| member_function_template::hash hash_member_fn_tmpl; |
| member_class_template::hash hash_member_class_tmpl; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_scope_type(t)); |
| |
| t.hashing_started(true); |
| |
| // Hash data members. |
| for (class_decl::data_members::const_iterator d = |
| t.get_non_static_data_members().begin(); |
| d != t.get_non_static_data_members().end(); |
| ++d) |
| v = hashing::combine_hashes(v, hash_data_member(**d)); |
| |
| // Do not hash member functions. All of them are not necessarily |
| // emitted per class, in a given TU so do not consider them when |
| // hashing a class. |
| |
| // Hash member function templates |
| for (member_function_templates::const_iterator f = |
| t.get_member_function_templates().begin(); |
| f != t.get_member_function_templates().end(); |
| ++f) |
| v = hashing::combine_hashes(v, hash_member_fn_tmpl(**f)); |
| |
| // Hash member class templates |
| for (member_class_templates::const_iterator c = |
| t.get_member_class_templates().begin(); |
| c != t.get_member_class_templates().end(); |
| ++c) |
| v = hashing::combine_hashes(v, hash_member_class_tmpl(**c)); |
| |
| t.hashing_started(false); |
| |
| return v; |
| }; |
| |
| /// Compute a hash for a @ref class_or_union |
| /// |
| /// @param t the class_or_union for which to compute the hash value. |
| /// |
| /// @return the computed hash value. |
| size_t |
| class_or_union::hash::operator()(const class_or_union *t) const |
| {return t ? operator()(*t) : 0;} |
| |
| /// Compute a hash for a @ref class_decl |
| /// |
| /// @param t the class_decl for which to compute the hash value. |
| /// |
| /// @return the computed hash value. |
| size_t |
| class_decl::hash::operator()(const class_decl& t) const |
| { |
| if (t.hashing_started() |
| || (t.get_is_declaration_only() && !t.get_definition_of_declaration())) |
| // All non-resolved decl-only types have a hash of zero. Their hash |
| // will differ from the resolved hash, but then at least, having |
| // it be zero will give a hint that we couldn't actually compute |
| // the hash. |
| return 0; |
| |
| |
| // If the type is decl-only and now has a definition, then hash its |
| // definition instead. |
| |
| if (t.get_is_declaration_only()) |
| { |
| ABG_ASSERT(t.get_definition_of_declaration()); |
| size_t v = operator()(*is_class_type(t.get_definition_of_declaration())); |
| return v; |
| } |
| |
| ABG_ASSERT(!t.get_is_declaration_only()); |
| |
| std::hash<string> hash_string; |
| class_decl::base_spec::hash hash_base; |
| class_or_union::hash hash_class_or_union; |
| |
| size_t v = hash_string(typeid(t).name()); |
| |
| t.hashing_started(true); |
| |
| // Hash bases. |
| for (class_decl::base_specs::const_iterator b = |
| t.get_base_specifiers().begin(); |
| b != t.get_base_specifiers().end(); |
| ++b) |
| { |
| class_decl_sptr cl = (*b)->get_base_class(); |
| v = hashing::combine_hashes(v, hash_base(**b)); |
| } |
| |
| v = hashing::combine_hashes(v, hash_class_or_union(t)); |
| |
| t.hashing_started(false); |
| |
| return v; |
| } |
| |
| /// Compute a hash for a @ref class_decl |
| /// |
| /// @param t the class_decl for which to compute the hash value. |
| /// |
| /// @return the computed hash value. |
| size_t |
| class_decl::hash::operator()(const class_decl* t) const |
| {return t ? operator()(*t) : 0;} |
| |
| struct template_parameter::hash |
| { |
| size_t |
| operator()(const template_parameter& t) const |
| { |
| // Let's avoid infinite recursion triggered from the fact that |
| // hashing a template parameter triggers hashing the enclosed |
| // template decl, which in turn triggers the hashing of its |
| // template parameters; so the initial template parameter that |
| // triggered the hashing could be hashed again ... |
| if (t.get_hashing_has_started()) |
| return 0; |
| |
| t.set_hashing_has_started(true); |
| |
| std::hash<unsigned> hash_unsigned; |
| std::hash<std::string> hash_string; |
| template_decl::hash hash_template_decl; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_unsigned(t.get_index())); |
| v = hashing::combine_hashes(v, hash_template_decl |
| (*t.get_enclosing_template_decl())); |
| |
| t.set_hashing_has_started(false); |
| |
| return v; |
| } |
| }; |
| |
| struct template_parameter::dynamic_hash |
| { |
| size_t |
| operator()(const template_parameter* t) const; |
| }; |
| |
| struct template_parameter::shared_ptr_hash |
| { |
| size_t |
| operator()(const shared_ptr<template_parameter> t) const |
| {return template_parameter::dynamic_hash()(t.get());} |
| }; |
| |
| size_t |
| template_decl::hash::operator()(const template_decl& t) const |
| { |
| std::hash<string> hash_string; |
| template_parameter::shared_ptr_hash hash_template_parameter; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_string(t.get_qualified_name())); |
| |
| for (list<template_parameter_sptr>::const_iterator p = |
| t.get_template_parameters().begin(); |
| p != t.get_template_parameters().end(); |
| ++p) |
| if (!(*p)->get_hashing_has_started()) |
| v = hashing::combine_hashes(v, hash_template_parameter(*p)); |
| |
| return v; |
| } |
| |
| struct type_tparameter::hash |
| { |
| size_t |
| operator()(const type_tparameter& t) const |
| { |
| std::hash<string> hash_string; |
| template_parameter::hash hash_template_parameter; |
| type_decl::hash hash_type; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_template_parameter(t)); |
| v = hashing::combine_hashes(v, hash_type(t)); |
| |
| return v; |
| } |
| }; |
| |
| /// Compute a hash value for a @ref non_type_tparameter |
| /// |
| /// @param t the non_type_tparameter for which to compute the value. |
| /// |
| /// @return the computed hash value. |
| size_t |
| non_type_tparameter::hash::operator()(const non_type_tparameter& t) const |
| { |
| template_parameter::hash hash_template_parameter; |
| std::hash<string> hash_string; |
| type_base::shared_ptr_hash hash_type; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_template_parameter(t)); |
| v = hashing::combine_hashes(v, hash_string(t.get_name())); |
| v = hashing::combine_hashes(v, hash_type(t.get_type())); |
| |
| return v; |
| } |
| |
| /// Compute a hash value for a @ref non_type_tparameter |
| /// |
| /// @param t the non_type_tparameter to compute the hash value for. |
| /// |
| /// @return the computed hash value. |
| size_t |
| non_type_tparameter::hash::operator()(const non_type_tparameter* t) const |
| {return t ? operator()(*t) : 0;} |
| |
| struct template_tparameter::hash |
| { |
| size_t |
| operator()(const template_tparameter& t) const |
| { |
| std::hash<string> hash_string; |
| type_tparameter::hash hash_template_type_parm; |
| template_decl::hash hash_template_decl; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_template_type_parm(t)); |
| v = hashing::combine_hashes(v, hash_template_decl(t)); |
| |
| return v; |
| } |
| }; |
| |
| size_t |
| template_parameter::dynamic_hash:: |
| operator()(const template_parameter* t) const |
| { |
| if (const template_tparameter* p = |
| dynamic_cast<const template_tparameter*>(t)) |
| return template_tparameter::hash()(*p); |
| else if (const type_tparameter* p = |
| dynamic_cast<const type_tparameter*>(t)) |
| return type_tparameter::hash()(*p); |
| if (const non_type_tparameter* p = |
| dynamic_cast<const non_type_tparameter*>(t)) |
| return non_type_tparameter::hash()(*p); |
| |
| // Poor man's fallback. |
| return template_parameter::hash()(*t); |
| } |
| |
| /// Compute a hash value for a @ref type_composition type. |
| /// |
| /// @param t the type_composition to compute the hash value for. |
| /// |
| /// @return the computed hash value. |
| size_t |
| type_composition::hash::operator()(const type_composition& t) const |
| { |
| std::hash<string> hash_string; |
| type_base::dynamic_hash hash_type; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_type(t.get_composed_type().get())); |
| return v; |
| } |
| |
| /// Compute a hash value for a @ref type_composition type. |
| /// |
| /// @param t the type_composition to compute the hash value for. |
| /// |
| /// @return the computed hash value. |
| size_t |
| type_composition::hash::operator()(const type_composition* t) const |
| {return t ? operator()(*t): 0;} |
| |
| size_t |
| function_tdecl::hash:: |
| operator()(const function_tdecl& t) const |
| { |
| std::hash<string> hash_string; |
| decl_base::hash hash_decl_base; |
| template_decl::hash hash_template_decl; |
| function_decl::hash hash_function_decl; |
| |
| size_t v = hash_string(typeid(t).name()); |
| |
| v = hashing::combine_hashes(v, hash_decl_base(t)); |
| v = hashing::combine_hashes(v, hash_template_decl(t)); |
| if (t.get_pattern()) |
| v = hashing::combine_hashes(v, hash_function_decl(*t.get_pattern())); |
| |
| return v; |
| } |
| |
| size_t |
| function_tdecl::shared_ptr_hash:: |
| operator()(const shared_ptr<function_tdecl> f) const |
| { |
| function_tdecl::hash hash_fn_tmpl_decl; |
| if (f) |
| return hash_fn_tmpl_decl(*f); |
| return 0; |
| } |
| |
| size_t |
| class_tdecl::hash:: |
| operator()(const class_tdecl& t) const |
| { |
| std::hash<string> hash_string; |
| decl_base::hash hash_decl_base; |
| template_decl::hash hash_template_decl; |
| class_decl::hash hash_class_decl; |
| |
| size_t v = hash_string(typeid(t).name()); |
| v = hashing::combine_hashes(v, hash_decl_base(t)); |
| v = hashing::combine_hashes(v, hash_template_decl(t)); |
| if (t.get_pattern()) |
| v = hashing::combine_hashes(v, hash_class_decl(*t.get_pattern())); |
| |
| return v; |
| } |
| |
| size_t |
| class_tdecl::shared_ptr_hash:: |
| operator()(const shared_ptr<class_tdecl> t) const |
| { |
| class_tdecl::hash hash_class_tmpl_decl; |
| |
| if (t) |
| return hash_class_tmpl_decl(*t); |
| return 0; |
| } |
| |
| /// A hashing function for type declarations. |
| /// |
| /// This function gets the dynamic type of the actual type |
| /// declaration and calls the right hashing function for that type. |
| /// |
| /// Note that each time a new type declaration kind is added to the |
| /// system, this function needs to be updated. For a given |
| /// inheritance hierarchy, make sure to handle the most derived type |
| /// first. |
| /// |
| /// FIXME: This hashing function is not maintained and is surely |
| /// broken in subtle ways. In pratice, the various *::hash functors |
| /// should be audited before they are used here. They should all |
| /// match what is done in the 'equals' functions in abg-ir.cc. |
| /// |
| /// @param t a pointer to the type declaration to be hashed |
| /// |
| /// @return the resulting hash |
| size_t |
| type_base::dynamic_hash::operator()(const type_base* t) const |
| { |
| if (t == 0) |
| return 0; |
| |
| if (const member_function_template* d = |
| dynamic_cast<const member_function_template*>(t)) |
| return member_function_template::hash()(*d); |
| if (const member_class_template* d = |
| dynamic_cast<const member_class_template*>(t)) |
| return member_class_template::hash()(*d); |
| if (const template_tparameter* d = |
| dynamic_cast<const template_tparameter*>(t)) |
| return template_tparameter::hash()(*d); |
| if (const type_tparameter* d = |
| dynamic_cast<const type_tparameter*>(t)) |
| return type_tparameter::hash()(*d); |
| if (const type_decl* d = dynamic_cast<const type_decl*> (t)) |
| return type_decl::hash()(*d); |
| if (const qualified_type_def* d = dynamic_cast<const qualified_type_def*>(t)) |
| return qualified_type_def::hash()(*d); |
| if (const pointer_type_def* d = dynamic_cast<const pointer_type_def*>(t)) |
| return pointer_type_def::hash()(*d); |
| if (const reference_type_def* d = dynamic_cast<const reference_type_def*>(t)) |
| return reference_type_def::hash()(*d); |
| if (const array_type_def* d = dynamic_cast<const array_type_def*>(t)) |
| return array_type_def::hash()(*d); |
| if (const enum_type_decl* d = dynamic_cast<const enum_type_decl*>(t)) |
| return enum_type_decl::hash()(*d); |
| if (const typedef_decl* d = dynamic_cast<const typedef_decl*>(t)) |
| return typedef_decl::hash()(*d); |
| if (const class_decl* d = dynamic_cast<const class_decl*>(t)) |
| return class_decl::hash()(*d); |
| if (const union_decl* d = dynamic_cast<const union_decl*>(t)) |
| return union_decl::hash()(*d); |
| if (const scope_type_decl* d = dynamic_cast<const scope_type_decl*>(t)) |
| return scope_type_decl::hash()(*d); |
| if (const method_type* d = dynamic_cast<const method_type*>(t)) |
| return method_type::hash()(*d); |
| if (const function_type* d = dynamic_cast<const function_type*>(t)) |
| return function_type::hash()(*d); |
| |
| // Poor man's fallback case. |
| return type_base::hash()(*t); |
| } |
| |
| size_t |
| type_base::shared_ptr_hash::operator()(const shared_ptr<type_base> t) const |
| {return type_base::dynamic_hash()(t.get());} |
| |
| }//end namespace abigail |