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 #ifndef LIBCURV_SC_TYPE_H
6 #define LIBCURV_SC_TYPE_H
7 
8 #include <libcurv/value.h>
9 #include <libcurv/type.h>
10 #include <ostream>
11 
12 namespace curv {
13 
14 // SC data types
15 struct SC_Type
16 {
17     static constexpr unsigned MAX_MAT_COUNT = 4; // max first dim of a matrix
18 
19 private:
20     Shared<const Type> type_;   // never null
SC_TypeSC_Type21     SC_Type(Shared<const Type> t) : type_(t) {}
22 public:
SC_TypeSC_Type23     SC_Type() : type_(Type::Error) {}
ErrorSC_Type24     static inline SC_Type Error() { return {}; }
25     static inline SC_Type Bool(unsigned n = 1) {
26         if (n == 1)
27             return {Type::Bool};
28         assert(n >= 2 && n <= 4);
29         return {make<List_Type>(n, Type::Bool)};
30     }
31     static inline SC_Type Bool32(unsigned n=1) {
32         if (n == 1)
33             return {Type::Bool32};
34         assert(n >= 2 && n <= 4);
35         return {make<List_Type>(n, Type::Bool32)};
36     }
37     static inline SC_Type Num(unsigned n = 1) {
38         if (n == 1)
39             return {Type::Num};
40         assert(n >= 2 && n <= 4);
41         return {make<List_Type>(n, Type::Num)};
42     }
VecSC_Type43     static inline SC_Type Vec(SC_Type base, unsigned n) {
44       #if !defined(NDEBUG)
45         auto plex = base.type_->plex_type_;
46       #endif
47         assert(plex == Plex_Type::Bool ||
48                plex == Plex_Type::Num ||
49                plex == Plex_Type::Bool32);
50         assert(n >= 1 && n <= 4);
51         return {make<List_Type>(n, base.type_)};
52     }
MatSC_Type53     static inline SC_Type Mat(int n) {
54         assert(n >= 2 && n <= 4);
55         return {make<List_Type>(n, make<List_Type>(n, Type::Num))};
56     }
57     static SC_Type List(SC_Type etype, unsigned n);
58 
59 public:
is_errorSC_Type60     inline bool is_error() const {
61         return type_->subtype_ == Ref_Value::sty_error_type;
62     }
63 
64     /*
65      * Boolean predicates
66      */
67     // Is a single Bool value. Consistent with Value::is_bool().
is_boolSC_Type68     inline bool is_bool() const {
69         return type_->plex_type_ == Plex_Type::Bool;
70     }
71     // Is a single Bool or vector of Bool (count 2-4). Not an array.
is_bool_or_vecSC_Type72     inline bool is_bool_or_vec() const {
73         auto plex = type_->plex_type_;
74         return plex >= Plex_Type::Bool && plex <= Plex_Type::Bool4;
75     }
76     // Is a single Bool32. Not an array.
is_bool32SC_Type77     inline bool is_bool32() const {
78         return type_->plex_type_ == Plex_Type::Bool32;
79     }
80     // Is a single Bool32 or vector of Bool32. Not an array.
is_bool32_or_vecSC_Type81     inline bool is_bool32_or_vec() const {
82         auto plex = type_->plex_type_;
83         return plex >= Plex_Type::Bool32 && plex <= Plex_Type::Bool4x32;
84     }
85     // Is a bool, a bool vec, a bool32, or a bool32 vec. Not an array.
is_bool_plexSC_Type86     inline bool is_bool_plex() const {
87         auto plex = type_->plex_type_;
88         return plex >= Plex_Type::Bool && plex <= Plex_Type::Bool4x32;
89     }
90     // Is a bool, a bool vec, a bool32, a bool32 vec, or array of same.
is_bool_tensorSC_Type91     inline bool is_bool_tensor() const {
92         auto plex = type_->plex_array_base()->plex_type_;
93         return plex >= Plex_Type::Bool && plex <= Plex_Type::Bool4x32;
94     }
95 
96     /*
97      * Numeric predicates
98      */
99     // Is a single number. Conforms to Value::is_num().
is_numSC_Type100     inline bool is_num() const {
101         return type_->plex_type_ == Plex_Type::Num;
102     }
103     // is a single number or vector
is_num_or_vecSC_Type104     inline bool is_num_or_vec() const {
105         auto plex = type_->plex_type_;
106         return plex >= Plex_Type::Num && plex <= Plex_Type::Vec4;
107     }
108     // Is a single number, vector, or matrix. Not an array.
is_num_plexSC_Type109     inline bool is_num_plex() const {
110         auto plex = type_->plex_type_;
111         return plex >= Plex_Type::Num && plex <= Plex_Type::Mat4;
112     }
113     // Is a number, a vector, a matrix, or an array of same.
is_num_tensorSC_Type114     inline bool is_num_tensor() const {
115         auto plex = type_->plex_array_base()->plex_type_;
116         return plex >= Plex_Type::Num && plex <= Plex_Type::Mat4;
117     }
is_num_vecSC_Type118     inline bool is_num_vec() const {
119         auto plex = type_->plex_type_;
120         return plex >= Plex_Type::Vec2 && plex <= Plex_Type::Vec4;
121     }
is_matSC_Type122     inline bool is_mat() const {
123         auto plex = type_->plex_type_;
124         return plex >= Plex_Type::Mat2 && plex <= Plex_Type::Mat4;
125     }
126 
127     // These functions view an SC_Type as a multi-D array of plexes.
128     // If plex_array_rank()==0 then the type is a plex.
plex_array_rankSC_Type129     inline unsigned plex_array_rank() const {
130         return type_->plex_array_rank();
131     }
plex_array_baseSC_Type132     inline SC_Type plex_array_base() const {
133         return SC_Type(type_->plex_array_base());
134     }
plex_array_dimSC_Type135     inline unsigned plex_array_dim(unsigned i) const {
136         return type_->plex_array_dim(i);
137     }
glsl_nameSC_Type138     inline const char* glsl_name() const {
139         return glsl_plex_type_name[unsigned(type_->plex_type_)];
140     }
141 
142     // a Plex type is one of the following 3 mutually exclusive cases:
is_scalar_plexSC_Type143     inline bool is_scalar_plex() const {
144         return type_->plex_type_ != Plex_Type::missing;
145     }
is_tupleSC_Type146     inline bool is_tuple() const { return false; }
is_structSC_Type147     inline bool is_struct() const { return false; }
148 
is_plexSC_Type149     inline bool is_plex() const {
150         return type_->plex_type_ != Plex_Type::missing;
151     }
is_listSC_Type152     inline bool is_list() const {
153         return type_->subtype_ == Ref_Value::sty_list_type;
154     }
is_scalar_or_vecSC_Type155     inline bool is_scalar_or_vec() const {
156         auto plex = type_->plex_type_;
157         return plex >= Plex_Type::Bool && plex <= Plex_Type::Vec4;
158     }
is_vecSC_Type159     inline bool is_vec() const {
160         auto plex = type_->plex_type_;
161         return (plex >= Plex_Type::Bool2 && plex <= Plex_Type::Bool4)
162             || (plex >= Plex_Type::Bool2x32 && plex <= Plex_Type::Bool4x32)
163             || (plex >= Plex_Type::Vec2 && plex <= Plex_Type::Vec4);
164     }
165 
166     // number of dimensions: 0 means a scalar (Num or Bool or Error)
rankSC_Type167     inline unsigned rank() const {
168         return type_->rank();
169     }
170     // First dimension, if type is a list, or 1 if type is a scalar.
countSC_Type171     inline unsigned count() const {
172         return type_->subtype_ == Ref_Value::sty_list_type
173             ? ((List_Type*)(&*type_))->count_
174             : 1;
175     }
176     // If this is an array, strip one dimension off of the type.
177     SC_Type elem_type() const;
178 
179     inline bool operator==(SC_Type rhs) const {
180         return Type::equal(*type_, *rhs.type_);
181     }
182     inline bool operator!=(SC_Type rhs) const {
183         return !(*this == rhs);
184     }
185     explicit operator bool () const noexcept {
186         return type_->subtype_ != Ref_Value::sty_error_type;
187     }
188 };
189 
190 std::ostream& operator<<(std::ostream& out, SC_Type);
191 
192 SC_Type sc_type_of(Value);
193 
194 SC_Type sc_unify_tensor_types(SC_Type a, SC_Type b);
195 
196 } // namespace
197 #endif // header guard
198