1 // Copyright(C) 1999-2020 National Technology & Engineering Solutions 2 // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with 3 // NTESS, the U.S. Government retains certain rights in this software. 4 // 5 // See packages/seacas/LICENSE for details 6 7 #include <Ioss_CompositeVariableType.h> 8 #include <Ioss_ConstructedVariableType.h> 9 #include <Ioss_NamedSuffixVariableType.h> 10 #include <Ioss_Utils.h> 11 #include <Ioss_VariableType.h> 12 #include <algorithm> 13 #include <cassert> 14 #include <cmath> 15 #include <cstddef> 16 #include <cstdio> 17 #include <cstdlib> 18 #include <cstring> 19 #include <fmt/ostream.h> 20 #include <map> 21 #include <sstream> 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 namespace Ioss { insert(const VTM_ValuePair & value,bool delete_me)27 void Registry::insert(const VTM_ValuePair &value, bool delete_me) 28 { 29 m_registry.insert(value); 30 if (delete_me) { 31 m_deleteThese.push_back(value.second); 32 } 33 } 34 ~Registry()35 Registry::~Registry() 36 { 37 for (auto &entry : m_deleteThese) { 38 delete entry; 39 } 40 } 41 42 VariableType::~VariableType() = default; 43 VariableType(const std::string & type,int comp_count,bool delete_me)44 VariableType::VariableType(const std::string &type, int comp_count, bool delete_me) 45 : name_(type), componentCount(comp_count) 46 { 47 std::string low_type = Utils::lowercase(type); 48 registry().insert(VTM_ValuePair(low_type, this), delete_me); 49 50 // Register uppercase version also 51 std::string up_type = Utils::uppercase(type); 52 registry().insert(VTM_ValuePair(up_type, this), false); 53 } 54 alias(const std::string & base,const std::string & syn)55 void VariableType::alias(const std::string &base, const std::string &syn) 56 { 57 registry().insert( 58 VTM_ValuePair(Utils::lowercase(syn), const_cast<VariableType *>(factory(base))), false); 59 // Register uppercase version also 60 std::string up_type = Utils::uppercase(syn); 61 registry().insert(VTM_ValuePair(up_type, const_cast<VariableType *>(factory(base))), false); 62 } 63 registry()64 Registry &VariableType::registry() 65 { 66 static Registry registry_; 67 return registry_; 68 } 69 70 /** \brief Get the names of variable types known to IOSS. 71 * 72 * \param[out] names The list of known variable type names. 73 * \returns The number of known variable types. 74 */ describe(NameList * names)75 int VariableType::describe(NameList *names) 76 { 77 int count = 0; 78 for (auto &entry : registry()) { 79 names->push_back(entry.first); 80 count++; 81 } 82 return count; 83 } 84 add_field_type_mapping(const std::string & raw_field,const std::string & raw_type)85 bool VariableType::add_field_type_mapping(const std::string &raw_field, 86 const std::string &raw_type) 87 { 88 // See if storage type 'type' exists... 89 std::string field = Utils::lowercase(raw_field); 90 std::string type = Utils::lowercase(raw_type); 91 if (registry().find(type) == registry().end()) { 92 return false; 93 } 94 95 // Add mapping. 96 return registry().customFieldTypes.insert(std::make_pair(field, type)).second; 97 } 98 create_named_suffix_field_type(const std::string & type_name,const std::vector<std::string> & suffices)99 bool VariableType::create_named_suffix_field_type(const std::string & type_name, 100 const std::vector<std::string> &suffices) 101 { 102 size_t count = suffices.size(); 103 if (count < 1) { 104 return false; 105 } 106 107 std::string low_name = Utils::lowercase(type_name); 108 // See if the variable already exists... 109 if (registry().find(low_name) != registry().end()) { 110 return false; 111 } 112 113 // Create the variable. Note that the 'true' argument means Ioss will delete 114 // the pointer. 115 auto var_type = new NamedSuffixVariableType(low_name, count, true); 116 117 for (size_t i = 0; i < count; i++) { 118 var_type->add_suffix(i + 1, suffices[i]); 119 } 120 return true; 121 } 122 get_field_type_mapping(const std::string & field,std::string * type)123 bool VariableType::get_field_type_mapping(const std::string &field, std::string *type) 124 { 125 // Returns true if a mapping exists, 'type' contains the mapped type. 126 // Returns false if no custom mapping exists for this field. 127 std::string low_field = Utils::lowercase(field); 128 129 if (registry().customFieldTypes.find(low_field) == registry().customFieldTypes.end()) { 130 return false; 131 } 132 133 *type = registry().customFieldTypes.find(low_field)->second; 134 return true; 135 } 136 factory(const std::string & raw_name,int copies)137 const VariableType *VariableType::factory(const std::string &raw_name, int copies) 138 { 139 VariableType *inst = nullptr; 140 std::string name = Utils::lowercase(raw_name); 141 auto iter = registry().find(name); 142 if (iter == registry().end()) { 143 bool can_construct = build_variable_type(name); 144 if (can_construct) { 145 iter = registry().find(name); 146 assert(iter != registry().end()); 147 inst = (*iter).second; 148 } 149 else { 150 std::ostringstream errmsg; 151 fmt::print(errmsg, "ERROR: The variable type '{}' is not supported.\n", raw_name); 152 IOSS_ERROR(errmsg); 153 } 154 } 155 else { 156 inst = (*iter).second; 157 } 158 159 if (copies != 1) { 160 inst = CompositeVariableType::composite_variable_type(inst, copies); 161 } 162 assert(inst != nullptr); 163 return inst; 164 } 165 factory(const std::vector<Suffix> & suffices)166 const VariableType *VariableType::factory(const std::vector<Suffix> &suffices) 167 { 168 size_t size = suffices.size(); 169 // Maximum suffix size is currently 5. 170 assert(size < 100000); 171 const VariableType *ivt = nullptr; 172 if (size <= 1) { 173 return nullptr; // All storage types must have at least 2 components. 174 } 175 176 bool match = false; 177 for (const auto &vtype : registry()) { 178 ivt = vtype.second; 179 if (ivt->suffix_count() == static_cast<int>(size)) { 180 if (ivt->match(suffices)) { 181 match = true; 182 break; 183 } 184 } 185 } 186 187 if (!match) { 188 match = true; 189 // Check if the suffices form a sequence (1,2,3,...,N) 190 // This indicates a "component" variable type that is 191 // constructed "on-the-fly" for use in Sierra 192 // 193 size_t width = Ioss::Utils::number_width(size); 194 for (size_t i = 0; i < size; i++) { 195 std::string digits = fmt::format("{:0{}}", i + 1, width); 196 if (!Ioss::Utils::str_equal(&suffices[i].m_data[0], digits)) { 197 match = false; 198 break; 199 } 200 } 201 if (match) { 202 // Create a new type. For now, assume that the base type is 203 // "Real" (Sierra type). The name of the new type is 204 // "Real[component_count]" 205 // Note that this type has not yet been constructed since 206 // it would have been found above. 207 ivt = new ConstructedVariableType(size, true); 208 } 209 else { 210 ivt = nullptr; 211 } 212 } 213 return ivt; 214 } 215 match(const std::vector<Suffix> & suffices)216 bool VariableType::match(const std::vector<Suffix> &suffices) const 217 { 218 bool result = true; 219 if (static_cast<int>(suffices.size()) == suffix_count()) { 220 for (int i = 0; i < suffix_count(); i++) { 221 if (suffices[i] != label(i + 1)) { 222 result = false; 223 break; 224 } 225 } 226 } 227 else { 228 result = false; 229 } 230 return result; 231 } 232 label_name(const std::string & base,int which,const char suffix_sep)233 std::string VariableType::label_name(const std::string &base, int which, 234 const char suffix_sep) const 235 { 236 std::string my_name = base; 237 std::string suffix = label(which, suffix_sep); 238 if (!suffix.empty()) { 239 if (suffix_sep != 0) { 240 my_name += suffix_sep; 241 } 242 my_name += suffix; 243 } 244 return my_name; 245 } 246 build_variable_type(const std::string & raw_type)247 bool VariableType::build_variable_type(const std::string &raw_type) 248 { 249 // See if this is a multi-component instance of a base type. 250 // An example would be REAL[2] which is a basic real type with 251 // two components. The suffices would be .0 and .1 252 253 std::string type = Utils::lowercase(raw_type); 254 255 // Step 0: 256 // See if the type contains '[' and ']' 257 char const *typestr = type.c_str(); 258 char const *lbrace = std::strchr(typestr, '['); 259 char const *rbrace = std::strrchr(typestr, ']'); 260 261 if (lbrace == nullptr || rbrace == nullptr) { 262 return false; 263 } 264 265 // Step 1: 266 // First, we split off the basename (REAL/INTEGER) from the component count 267 // ([2]) 268 // and see if the basename is a valid variable type and the count is a 269 // valid integer. 270 size_t len = type.length() + 1; 271 auto typecopy = new char[len]; 272 Utils::copy_string(typecopy, typestr, len); 273 274 char *base = std::strtok(typecopy, "[]"); 275 assert(base != nullptr); 276 auto iter = VariableType::registry().find(base); 277 if (iter == registry().end()) { 278 delete[] typecopy; 279 return false; 280 } 281 282 char *countstr = std::strtok(nullptr, "[]"); 283 assert(countstr != nullptr); 284 int count = std::atoi(countstr); 285 if (count <= 0) { 286 delete[] typecopy; 287 return false; 288 } 289 290 // We now know we have a valid base type and an integer 291 // specifying the number of 'components' in our new type. 292 // Create the new type and register it in the registry... 293 new ConstructedVariableType(type, count, true); 294 delete[] typecopy; 295 return true; 296 } 297 numeric_label(int which,int ncomp,const std::string & name)298 std::string VariableType::numeric_label(int which, int ncomp, const std::string &name) 299 { 300 if (ncomp >= 100000) { 301 std::ostringstream errmsg; 302 fmt::print(errmsg, 303 "ERROR: Variable '{}' has {:L} components which is larger than the current maximum" 304 " of 100,000. Please contact developer.\n", 305 name, ncomp); 306 IOSS_ERROR(errmsg); 307 } 308 309 size_t width = Ioss::Utils::number_width(ncomp); 310 std::string digits = fmt::format("{:0{}}", which, width); 311 return digits; 312 } 313 } // namespace Ioss 314