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