blob: ffa529e805cdd86d5f69186617755f8f27e7d5fa [file] [log] [blame]
// 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