1 // Copyright 2016-2021 Doug Moen
2 // Licensed under the Apache License, version 2.0
3 // See accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0
4 
5 #include <libcurv/function.h>
6 #include <libcurv/meaning.h>
7 #include <boost/functional/hash.hpp>
8 
9 namespace curv
10 {
11 
hash() const12 size_t Operation::hash() const noexcept
13 {
14     return size_t(this);
15 }
hash_eq(const Operation & rhs) const16 bool Operation::hash_eq(const Operation& rhs) const noexcept
17 {
18     return this == &rhs;
19 }
20 
hash() const21 size_t Prefix_Expr_Base::hash() const noexcept
22 {
23     size_t result = typeid(*this).hash_code();
24     boost::hash_combine(result, arg_->hash());
25     return result;
26 }
hash_eq(const Operation & rhs) const27 bool Prefix_Expr_Base::hash_eq(const Operation& rhs) const noexcept
28 {
29     if (typeid(rhs) == typeid(*this)) {
30         auto& r = dynamic_cast<const Prefix_Expr_Base&>(rhs);
31         return arg_->hash_eq(*r.arg_);
32     }
33     return false;
34 }
35 
36 #define GEN_BINARY_HASH(Class) \
37 size_t Class::hash() const noexcept \
38 { \
39     size_t result = arg1_->hash(); \
40     boost::hash_combine(result, arg2_->hash()); \
41     boost::hash_combine(result, #Class); \
42     return result; \
43 } \
44 bool Class::hash_eq(const Operation& rhs) const noexcept \
45 { \
46     auto r = dynamic_cast<const Class*>(&rhs); \
47     if (r) \
48         return arg1_->hash_eq(*r->arg1_) \
49             && arg2_->hash_eq(*r->arg2_); \
50     return false; \
51 }
52 
53 #define arg1_ func_
54 #define arg2_ arg_
55 GEN_BINARY_HASH(Call_Expr)
56 #undef arg1_
57 #undef arg2_
58 
59 #define GEN_TERNARY_HASH(Class) \
60 size_t Class::hash() const noexcept \
61 { \
62     size_t result = arg1_->hash(); \
63     boost::hash_combine(result, arg2_->hash()); \
64     boost::hash_combine(result, arg3_->hash()); \
65     boost::hash_combine(result, #Class); \
66     return result; \
67 } \
68 bool Class::hash_eq(const Operation& rhs) const noexcept \
69 { \
70     auto r = dynamic_cast<const Class*>(&rhs); \
71     if (r) \
72         return arg1_->hash_eq(*r->arg1_) \
73             && arg2_->hash_eq(*r->arg2_) \
74             && arg3_->hash_eq(*r->arg3_); \
75     return false; \
76 }
77 
GEN_TERNARY_HASH(If_Else_Op)78 GEN_TERNARY_HASH(If_Else_Op)
79 
80 size_t Constant::hash() const noexcept
81 {
82     size_t result = value_.hash();
83     boost::hash_combine(result, "Constant");
84     return result;
85 }
hash_eq(const Operation & rhs) const86 bool Constant::hash_eq(const Operation& rhs) const noexcept
87 {
88     auto r = dynamic_cast<const Constant*>(&rhs);
89     if (r)
90         return value_.hash_eq(r->value_);
91     return false;
92 }
93 
hash() const94 size_t Local_Data_Ref::hash() const noexcept
95 {
96     size_t result = slot_;
97     boost::hash_combine(result, "Local_Data_Ref");
98     return result;
99 }
hash_eq(const Operation & rhs) const100 bool Local_Data_Ref::hash_eq(const Operation& rhs) const noexcept
101 {
102     auto r = dynamic_cast<const Local_Data_Ref*>(&rhs);
103     if (r)
104         return slot_ == r->slot_;
105     return false;
106 }
107 
hash() const108 size_t List_Expr_Base::hash() const noexcept
109 {
110     std::hash<const char*> hasher;
111     size_t result = hasher("List");
112     for (size_t i = 0; i < size_; ++i)
113         boost::hash_combine(result, array_[i]->hash());
114     return result;
115 }
hash_eq(const Operation & rhs) const116 bool List_Expr_Base::hash_eq(const Operation& rhs) const noexcept
117 {
118     auto r = dynamic_cast<const List_Expr_Base*>(&rhs);
119     if (r) {
120         if (size_ != r->size_) return false;
121         for (size_t i = 0; i < size_; ++i) {
122             if (!array_[i]->hash_eq(*r->array_[i]))
123                 return false;
124         }
125         return true;
126     }
127     return false;
128 }
129 
130 } // namespace curv
131