1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md
4 
5 
6 #include <cstdio>
7 #include <cstdlib>
8 #include <string>
9 
10 #include <OpenImageIO/Imath.h>
11 #include <OpenImageIO/dassert.h>
12 #include <OpenImageIO/strutil.h>
13 #include <OpenImageIO/typedesc.h>
14 #include <OpenImageIO/ustring.h>
15 
16 
17 OIIO_NAMESPACE_BEGIN
18 
TypeDesc(string_view typestring)19 TypeDesc::TypeDesc(string_view typestring)
20     : basetype(UNKNOWN)
21     , aggregate(SCALAR)
22     , vecsemantics(NOXFORM)
23     , reserved(0)
24     , arraylen(0)
25 {
26     fromstring(typestring);
27 }
28 
29 
30 
31 namespace {
32 
33 static int basetype_size[TypeDesc::LASTBASE] = {
34     0,                           // UNKNOWN
35     0,                           // VOID
36     sizeof(unsigned char),       // UCHAR
37     sizeof(char),                // CHAR
38     sizeof(unsigned short),      // USHORT
39     sizeof(short),               // SHORT
40     sizeof(unsigned int),        // UINT
41     sizeof(int),                 // INT
42     sizeof(unsigned long long),  // ULONGLONG
43     sizeof(long long),           // LONGLONG
44     sizeof(float) / 2,           // HALF
45     sizeof(float),               // FLOAT
46     sizeof(double),              // DOUBLE
47     sizeof(char*),               // STRING
48     sizeof(void*)                // PTR
49 };
50 
51 }
52 
53 size_t
basesize() const54 TypeDesc::basesize() const noexcept
55 {
56     if (basetype >= TypeDesc::LASTBASE)
57         return 0;
58     OIIO_DASSERT(basetype < TypeDesc::LASTBASE);
59     return basetype_size[basetype];
60 }
61 
62 
63 
64 bool
is_floating_point() const65 TypeDesc::is_floating_point() const noexcept
66 {
67     static bool isfloat[TypeDesc::LASTBASE] = {
68         0,  // UNKNOWN
69         0,  // VOID
70         0,  // UCHAR
71         0,  // CHAR
72         0,  // USHORT
73         0,  // SHORT
74         0,  // UINT
75         0,  // INT
76         0,  // ULONGLONG
77         0,  // LONGLONG
78         1,  // HALF
79         1,  // FLOAT
80         1,  // DOUBLE
81         0,  // STRING
82         0   // PTR
83     };
84     OIIO_DASSERT(basetype < TypeDesc::LASTBASE);
85     return isfloat[basetype];
86 }
87 
88 
89 
90 bool
is_signed() const91 TypeDesc::is_signed() const noexcept
92 {
93     static bool issigned[TypeDesc::LASTBASE] = {
94         0,  // UNKNOWN
95         0,  // VOID
96         0,  // UCHAR
97         1,  // CHAR
98         0,  // USHORT
99         1,  // SHORT
100         0,  // UINT
101         1,  // INT
102         0,  // ULONGLONG
103         1,  // LONGLONG
104         1,  // HALF
105         1,  // FLOAT
106         1,  // DOUBLE
107         0,  // STRING
108         0   // PTR
109     };
110     OIIO_DASSERT(basetype < TypeDesc::LASTBASE);
111     return issigned[basetype];
112 }
113 
114 
115 
116 namespace {
117 
118 static const char* basetype_name[] = {
119     "unknown",  // UNKNOWN
120     "void",     // VOID/NONE
121     "uint8",    // UCHAR
122     "int8",     // CHAR
123     "uint16",   // USHORT
124     "int16",    // SHORT
125     "uint",     // UINT
126     "int",      // INT
127     "uint64",   // ULONGLONG
128     "int64",    // LONGLONG
129     "half",     // HALF
130     "float",    // FLOAT
131     "double",   // DOUBLE
132     "string",   // STRING
133     "pointer"   // PTR
134 };
135 
136 static const char* basetype_code[] = {
137     "unknown",  // UNKNOWN
138     "void",     // VOID/NONE
139     "uc",       // UCHAR
140     "c",        // CHAR
141     "us",       // USHORT
142     "s",        // SHORT
143     "ui",       // UINT
144     "i",        // INT
145     "ull",      // ULONGLONG
146     "ll",       // LONGLONG
147     "h",        // HALF
148     "f",        // FLOAT
149     "d",        // DOUBLE
150     "str",      // STRING
151     "ptr"       // PTR
152 };
153 
154 }  // namespace
155 
156 const char*
c_str() const157 TypeDesc::c_str() const
158 {
159     // FIXME : how about a per-thread cache of the last one or two, so
160     // we don't have to re-assemble strings all the time?
161 
162     // Timecode and Keycode are hard coded
163     static constexpr TypeDesc TypeTimeCodeAlt(UINT, VEC2, TIMECODE);
164     if (*this == TypeTimeCode || *this == TypeTimeCodeAlt)
165         return ustring("timecode").c_str();
166     else if (*this == TypeKeyCode)
167         return ustring("keycode").c_str();
168 
169     std::string result;
170     if (aggregate == SCALAR)
171         result = basetype_name[basetype];
172     // else if (aggregate == MATRIX44 && basetype == FLOAT)
173     //     result = "matrix";
174     // else if (aggregate == MATRIX33 && basetype == FLOAT)
175     //     result = "matrix33";
176     // else if (aggregate == VEC2 && basetype == FLOAT && vecsemantics == NOXFORM)
177     //     result = "float2";
178     // else if (aggregate == VEC4 && basetype == FLOAT && vecsemantics == NOXFORM)
179     //     result = "float4";
180     else if (vecsemantics == NOXFORM) {
181         switch (aggregate) {
182         case VEC2: result = "float2"; break;
183         case VEC3: result = "float3"; break;
184         case VEC4: result = "float4"; break;
185         case MATRIX33: result = "matrix33"; break;
186         case MATRIX44: result = "matrix"; break;
187         }
188         if (basetype != FLOAT)
189             result += basetype_code[basetype];
190     } else {
191         // Special names for vector semantics
192         const char* vec = "";
193         switch (vecsemantics) {
194         case COLOR: vec = "color"; break;
195         case POINT: vec = "point"; break;
196         case VECTOR: vec = "vector"; break;
197         case NORMAL: vec = "normal"; break;
198         case RATIONAL: vec = "rational"; break;
199         default: OIIO_DASSERT(0 && "Invalid vector semantics");
200         }
201         const char* agg = "";
202         switch (aggregate) {
203         case VEC2: agg = "2"; break;
204         case VEC4: agg = "4"; break;
205         case MATRIX33: agg = "matrix33"; break;
206         case MATRIX44: agg = "matrix44"; break;
207         }
208         result = std::string(vec) + std::string(agg);
209         if (basetype != FLOAT)
210             result += basetype_code[basetype];
211     }
212     if (arraylen > 0)
213         result += Strutil::sprintf("[%d]", arraylen);
214     else if (arraylen < 0)
215         result += "[]";
216     return ustring(result).c_str();
217 }
218 
219 
220 
221 // Copy src into dst until you hit the end, find a delimiter charcter,
222 // or have copied maxlen-1 characters, whichever comes first.  Add a
223 // terminating null charcter.  Return the number of characters copied.
224 inline size_t
copy_until(const char * src,const char * delim,char * dst,size_t maxlen)225 copy_until(const char* src, const char* delim, char* dst, size_t maxlen)
226 {
227     size_t i = 0;
228     while (src[i] && i < maxlen - 1) {
229         bool found_delim = false;
230         for (int d = 0; delim[d]; ++d)
231             if (src[i] == delim[d])
232                 found_delim = true;
233         if (found_delim)
234             break;
235         dst[i] = src[i];
236         ++i;
237     }
238     dst[i] = 0;
239     return i;
240 }
241 
242 
243 
244 size_t
fromstring(string_view typestring)245 TypeDesc::fromstring(string_view typestring)
246 {
247     *this            = TypeDesc::UNKNOWN;
248     string_view orig = typestring;
249     if (typestring.empty()) {
250         return 0;
251     }
252 
253     // The first "word" should be a type name.
254     string_view type = Strutil::parse_identifier(typestring);
255 
256     // Check the scalar types in our table above
257     TypeDesc t;
258     for (int i = 0; i < LASTBASE; ++i) {
259         if (type == basetype_name[i]) {
260             t.basetype = i;
261             break;
262         }
263     }
264 
265     // Some special case names for aggregates
266     if (t.basetype != UNKNOWN) {
267         // already solved
268     } else if (type == "color")
269         t = TypeColor;
270     else if (type == "point")
271         t = TypePoint;
272     else if (type == "vector")
273         t = TypeVector;
274     else if (type == "normal")
275         t = TypeNormal;
276     else if (type == "matrix33")
277         t = TypeMatrix33;
278     else if (type == "matrix" || type == "matrix44")
279         t = TypeMatrix44;
280     else if (type == "vector2")
281         t = TypeVector2;
282     else if (type == "vector4")
283         t = TypeVector4;
284     else if (type == "timecode")
285         t = TypeTimeCode;
286     else if (type == "rational")
287         t = TypeRational;
288     else {
289         return 0;  // unknown
290     }
291 
292     // Is there an array length following the type name?
293     if (Strutil::parse_char(typestring, '[')) {
294         int arraylen = -1;
295         Strutil::parse_int(typestring, arraylen);
296         if (!Strutil::parse_char(typestring, ']'))
297             return 0;  // malformed
298         t.arraylen = arraylen;
299     }
300 
301     *this = t;
302     return orig.length() - typestring.length();
303 }
304 
305 
306 
tostring_formatting(const char * int_fmt,const char * float_fmt,const char * string_fmt,const char * ptr_fmt,const char * aggregate_begin,const char * aggregate_end,const char * aggregate_sep,const char * array_begin,const char * array_end,const char * array_sep,int flags,const char * uint_fmt)307 tostring_formatting::tostring_formatting(
308     const char* int_fmt, const char* float_fmt, const char* string_fmt,
309     const char* ptr_fmt, const char* aggregate_begin, const char* aggregate_end,
310     const char* aggregate_sep, const char* array_begin, const char* array_end,
311     const char* array_sep, int flags, const char* uint_fmt)
312     : int_fmt(int_fmt)
313     , float_fmt(float_fmt)
314     , string_fmt(string_fmt)
315     , ptr_fmt(ptr_fmt)
316     , aggregate_begin(aggregate_begin)
317     , aggregate_end(aggregate_end)
318     , aggregate_sep(aggregate_sep)
319     , array_begin(array_begin)
320     , array_end(array_end)
321     , array_sep(array_sep)
322     , flags(flags)
323     , uint_fmt(uint_fmt)
324 {
325 }
326 
327 
328 
tostring_formatting(Notation notation,const char * int_fmt,const char * uint_fmt,const char * float_fmt,const char * string_fmt,const char * ptr_fmt,const char * aggregate_begin,const char * aggregate_end,const char * aggregate_sep,const char * array_begin,const char * array_end,const char * array_sep,int flags)329 tostring_formatting::tostring_formatting(
330     Notation notation, const char* int_fmt, const char* uint_fmt,
331     const char* float_fmt, const char* string_fmt, const char* ptr_fmt,
332     const char* aggregate_begin, const char* aggregate_end,
333     const char* aggregate_sep, const char* array_begin, const char* array_end,
334     const char* array_sep, int flags)
335     : tostring_formatting(int_fmt, float_fmt, string_fmt, ptr_fmt,
336                           aggregate_begin, aggregate_end, aggregate_sep,
337                           array_begin, array_end, array_sep, flags, uint_fmt)
338 {
339     use_sprintf = false;
340 }
341 
342 
343 
344 template<class T>
345 static std::string
sprint_type(TypeDesc type,const char * format,const tostring_formatting & fmt,const T * v)346 sprint_type(TypeDesc type, const char* format, const tostring_formatting& fmt,
347             const T* v)
348 {
349     std::string val;
350     if (type.arraylen)
351         val += fmt.array_begin;
352     const size_t n = type.arraylen ? type.arraylen : 1;
353     for (size_t i = 0; i < n; ++i) {
354         if (type.aggregate > 1)
355             val += fmt.aggregate_begin;
356         for (int j = 0; j < (int)type.aggregate; ++j, ++v) {
357             val += Strutil::sprintf(format, *v);
358             if (type.aggregate > 1 && j < type.aggregate - 1)
359                 val += fmt.aggregate_sep;
360         }
361         if (type.aggregate > 1)
362             val += fmt.aggregate_end;
363         if (i < n - 1)
364             val += fmt.array_sep;
365     }
366     if (type.arraylen)
367         val += fmt.array_end;
368     return val;
369 }
370 
371 
372 
373 static std::string
sprint_type(TypeDesc type,const char * format,const tostring_formatting & fmt,const char ** v)374 sprint_type(TypeDesc type, const char* format, const tostring_formatting& fmt,
375             const char** v)
376 {
377     std::string val;
378     if (type.arraylen)
379         val += fmt.array_begin;
380     const size_t n = type.arraylen ? type.arraylen : 1;
381     for (size_t i = 0; i < n; ++i) {
382         if (type.aggregate > 1)
383             val += fmt.aggregate_begin;
384         for (int j = 0; j < (int)type.aggregate; ++j, ++v) {
385             if (fmt.flags & tostring_formatting::escape_strings)
386                 val += Strutil::sprintf(format, *v ? Strutil::escape_chars(*v)
387                                                    : std::string());
388             else
389                 val += Strutil::sprintf(format, *v ? *v : "");
390             if (type.aggregate > 1 && j < type.aggregate - 1)
391                 val += fmt.aggregate_sep;
392         }
393         if (type.aggregate > 1)
394             val += fmt.aggregate_end;
395         if (i < n - 1)
396             val += fmt.array_sep;
397     }
398     if (type.arraylen)
399         val += fmt.array_end;
400     return val;
401 }
402 
403 
404 
405 template<class T>
406 static std::string
format_type(TypeDesc type,const char * format,const tostring_formatting & fmt,const T * v)407 format_type(TypeDesc type, const char* format, const tostring_formatting& fmt,
408             const T* v)
409 {
410     std::string val;
411     if (type.arraylen)
412         val += fmt.array_begin;
413     const size_t n = type.arraylen ? type.arraylen : 1;
414     for (size_t i = 0; i < n; ++i) {
415         if (type.aggregate > 1)
416             val += fmt.aggregate_begin;
417         for (int j = 0; j < (int)type.aggregate; ++j, ++v) {
418             val += Strutil::fmt::format(format, *v);
419             if (type.aggregate > 1 && j < type.aggregate - 1)
420                 val += fmt.aggregate_sep;
421         }
422         if (type.aggregate > 1)
423             val += fmt.aggregate_end;
424         if (i < n - 1)
425             val += fmt.array_sep;
426     }
427     if (type.arraylen)
428         val += fmt.array_end;
429     return val;
430 }
431 
432 
433 
434 static std::string
format_type(TypeDesc type,const char * format,const tostring_formatting & fmt,const char ** v)435 format_type(TypeDesc type, const char* format, const tostring_formatting& fmt,
436             const char** v)
437 {
438     std::string val;
439     if (type.arraylen)
440         val += fmt.array_begin;
441     const size_t n = type.arraylen ? type.arraylen : 1;
442     for (size_t i = 0; i < n; ++i) {
443         if (type.aggregate > 1)
444             val += fmt.aggregate_begin;
445         for (int j = 0; j < (int)type.aggregate; ++j, ++v) {
446             if (fmt.flags & tostring_formatting::escape_strings)
447                 val += Strutil::fmt::format(format,
448                                             *v ? Strutil::escape_chars(*v)
449                                                : std::string());
450             else
451                 val += Strutil::fmt::format(format, *v ? *v : "");
452             if (type.aggregate > 1 && j < type.aggregate - 1)
453                 val += fmt.aggregate_sep;
454         }
455         if (type.aggregate > 1)
456             val += fmt.aggregate_end;
457         if (i < n - 1)
458             val += fmt.array_sep;
459     }
460     if (type.arraylen)
461         val += fmt.array_end;
462     return val;
463 }
464 
465 
466 
467 // From OpenEXR
468 inline unsigned int
bitField(unsigned int value,int minBit,int maxBit)469 bitField(unsigned int value, int minBit, int maxBit)
470 {
471     int shift         = minBit;
472     unsigned int mask = (~(~0U << (maxBit - minBit + 1)) << minBit);
473     return (value & mask) >> shift;
474 }
475 
476 
477 // From OpenEXR
478 inline int
bcdToBinary(unsigned int bcd)479 bcdToBinary(unsigned int bcd)
480 {
481     return int((bcd & 0x0f) + 10 * ((bcd >> 4) & 0x0f));
482 }
483 
484 
485 
486 std::string
tostring(TypeDesc type,const void * data,const tostring_formatting & fmt)487 tostring(TypeDesc type, const void* data, const tostring_formatting& fmt)
488 {
489     // Perhaps there is a way to use CType<> with a dynamic argument?
490     switch (type.basetype) {
491     case TypeDesc::UNKNOWN:
492         return fmt.use_sprintf
493                    ? sprint_type(type, fmt.ptr_fmt, fmt, (void**)data)
494                    : format_type(type, fmt.ptr_fmt, fmt, (void**)data);
495     case TypeDesc::NONE:
496         return fmt.use_sprintf ? sprint_type(type, "None", fmt, (void**)data)
497                                : format_type(type, "None", fmt, (void**)data);
498     case TypeDesc::UCHAR:
499         return fmt.use_sprintf
500                    ? sprint_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
501                                  (unsigned char*)data)
502                    : format_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
503                                  (unsigned char*)data);
504     case TypeDesc::CHAR:
505         return fmt.use_sprintf
506                    ? sprint_type(type, fmt.int_fmt, fmt, (char*)data)
507                    : format_type(type, fmt.int_fmt, fmt, (char*)data);
508     case TypeDesc::USHORT:
509         return fmt.use_sprintf
510                    ? sprint_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
511                                  (uint16_t*)data)
512                    : format_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
513                                  (uint16_t*)data);
514     case TypeDesc::SHORT:
515         return fmt.use_sprintf
516                    ? sprint_type(type, fmt.int_fmt, fmt, (short*)data)
517                    : format_type(type, fmt.int_fmt, fmt, (short*)data);
518     case TypeDesc::UINT:
519         if (type.vecsemantics == TypeDesc::RATIONAL
520             && type.aggregate == TypeDesc::VEC2) {
521             std::string out;
522             const uint32_t* val = (const uint32_t*)data;
523             for (size_t i = 0, e = type.numelements(); i < e; ++i, val += 2) {
524                 if (i)
525                     out += ", ";
526                 out += Strutil::sprintf("%u/%u", val[0], val[1]);
527             }
528             return out;
529         } else if (type == TypeTimeCode) {
530             // Replicating the logic in OpenEXR, but this prevents us from
531             // needing to link to libIlmImf just to do this.
532             unsigned int t = *(unsigned int*)data;
533             int hours      = bcdToBinary(bitField(t, 24, 29));
534             int minutes    = bcdToBinary(bitField(t, 16, 22));
535             int seconds    = bcdToBinary(bitField(t, 8, 14));
536             int frame      = bcdToBinary(bitField(t, 0, 5));
537             return Strutil::sprintf("%02d:%02d:%02d:%02d", hours, minutes,
538                                     seconds, frame);
539         }
540         return fmt.use_sprintf
541                    ? sprint_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
542                                  (unsigned int*)data)
543                    : format_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
544                                  (unsigned int*)data);
545     case TypeDesc::INT:
546         if (type.elementtype() == TypeRational) {
547             std::string out;
548             const int* val = (const int*)data;
549             for (size_t i = 0, e = type.numelements(); i < e; ++i, val += 2) {
550                 if (i)
551                     out += ", ";
552                 out += Strutil::sprintf("%d/%d", val[0], val[1]);
553             }
554             return out;
555         }
556         return fmt.use_sprintf
557                    ? sprint_type(type, fmt.int_fmt, fmt, (int*)data)
558                    : format_type(type, fmt.int_fmt, fmt, (int*)data);
559     case TypeDesc::UINT64:
560         return fmt.use_sprintf
561                    ? sprint_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
562                                  (const uint64_t*)data)
563                    : format_type(type, fmt.uint_fmt ? fmt.uint_fmt : "%u", fmt,
564                                  (const uint64_t*)data);
565     case TypeDesc::INT64:
566         return fmt.use_sprintf
567                    ? sprint_type(type, fmt.int_fmt, fmt, (const int64_t*)data)
568                    : format_type(type, fmt.int_fmt, fmt, (const int64_t*)data);
569     case TypeDesc::HALF:
570         return fmt.use_sprintf
571                    ? sprint_type(type, fmt.float_fmt, fmt, (const half*)data)
572                    : format_type(type, fmt.float_fmt, fmt, (const half*)data);
573     case TypeDesc::FLOAT:
574         return fmt.use_sprintf
575                    ? sprint_type(type, fmt.float_fmt, fmt, (const float*)data)
576                    : format_type(type, fmt.float_fmt, fmt, (const float*)data);
577     case TypeDesc::DOUBLE:
578         return fmt.use_sprintf
579                    ? sprint_type(type, fmt.float_fmt, fmt, (const double*)data)
580                    : format_type(type, fmt.float_fmt, fmt, (const double*)data);
581     case TypeDesc::STRING:
582         if (!type.is_array()
583             && !(fmt.flags & tostring_formatting::quote_single_string))
584             return *(const char**)data;
585         return fmt.use_sprintf
586                    ? sprint_type(type, fmt.string_fmt, fmt, (const char**)data)
587                    : format_type(type, fmt.string_fmt, fmt, (const char**)data);
588     case TypeDesc::PTR:
589         return fmt.use_sprintf
590                    ? sprint_type(type, fmt.ptr_fmt, fmt, (void**)data)
591                    : format_type(type, fmt.ptr_fmt, fmt, (void**)data);
592     default:
593 #ifndef NDEBUG
594         return Strutil::sprintf("<unknown data type> (base %d, agg %d vec %d)",
595                                 type.basetype, type.aggregate,
596                                 type.vecsemantics);
597 #endif
598         break;
599     }
600     return "";
601 }
602 
603 
604 
605 // Old deprecated one
606 std::string
tostring(TypeDesc type,const void * data,const char * float_fmt,const char * string_fmt,const char aggregate_delim[2],const char * aggregate_sep,const char array_delim[2],const char * array_sep)607 tostring(TypeDesc type, const void* data, const char* float_fmt,
608          const char* string_fmt, const char aggregate_delim[2],
609          const char* aggregate_sep, const char array_delim[2],
610          const char* array_sep)
611 {
612     tostring_formatting fmt("%d", float_fmt, string_fmt, "%p",
613                             std::string(aggregate_delim + 0, 1).c_str(),
614                             std::string(aggregate_delim + 1, 1).c_str(),
615                             aggregate_sep,
616                             std::string(array_delim + 0, 1).c_str(),
617                             std::string(array_delim + 1, 1).c_str(), array_sep);
618     return tostring(type, data, fmt);
619 }
620 
621 
622 
623 namespace {
624 
625 template<typename T = int>
626 static bool
to_ints(TypeDesc srctype,const void * src,T * dst,size_t n=1)627 to_ints(TypeDesc srctype, const void* src, T* dst, size_t n = 1)
628 {
629     if (srctype.basetype == TypeDesc::UINT) {
630         for (size_t i = 0; i < n; ++i)
631             dst[i] = T(((const unsigned int*)src)[i]);
632         return true;
633     }
634     if (srctype.basetype == TypeDesc::INT16) {
635         for (size_t i = 0; i < n; ++i)
636             dst[i] = T(((const short*)src)[i]);
637         return true;
638     }
639     if (srctype.basetype == TypeDesc::UINT16) {
640         for (size_t i = 0; i < n; ++i)
641             dst[i] = T(((const unsigned short*)src)[i]);
642         return true;
643     }
644     if (srctype.basetype == TypeDesc::INT8) {
645         for (size_t i = 0; i < n; ++i)
646             dst[i] = T(((const char*)src)[i]);
647         return true;
648     }
649     if (srctype.basetype == TypeDesc::UINT8) {
650         for (size_t i = 0; i < n; ++i)
651             dst[i] = T(((const unsigned char*)src)[i]);
652         return true;
653     }
654     if (srctype.basetype == TypeDesc::INT64) {
655         for (size_t i = 0; i < n; ++i)
656             dst[i] = T(((const long long*)src)[i]);
657         return true;
658     }
659     if (srctype.basetype == TypeDesc::UINT64) {
660         for (size_t i = 0; i < n; ++i)
661             dst[i] = T(((const unsigned long long*)src)[i]);
662         return true;
663     }
664     return false;
665 }
666 
667 
668 template<typename T = float>
669 static bool
to_floats(TypeDesc srctype,const void * src,T * dst,size_t n=1)670 to_floats(TypeDesc srctype, const void* src, T* dst, size_t n = 1)
671 {
672     if (srctype.basetype == TypeDesc::FLOAT) {
673         for (size_t i = 0; i < n; ++i)
674             dst[i] = T(((const float*)src)[i]);
675         return true;
676     }
677     if (srctype.basetype == TypeDesc::HALF) {
678         for (size_t i = 0; i < n; ++i)
679             dst[i] = T(((const half*)src)[i]);
680         return true;
681     }
682     if (srctype.basetype == TypeDesc::DOUBLE) {
683         for (size_t i = 0; i < n; ++i)
684             dst[i] = T(((const double*)src)[i]);
685         return true;
686     }
687     if (srctype.basetype == TypeDesc::UINT) {
688         for (size_t i = 0; i < n; ++i)
689             dst[i] = T(((const unsigned int*)src)[i]);
690         return true;
691     }
692     if (srctype.basetype == TypeDesc::INT16) {
693         for (size_t i = 0; i < n; ++i)
694             dst[i] = T(((const short*)src)[i]);
695         return true;
696     }
697     if (srctype.basetype == TypeDesc::UINT16) {
698         for (size_t i = 0; i < n; ++i)
699             dst[i] = T(((const unsigned short*)src)[i]);
700         return true;
701     }
702     if (srctype.basetype == TypeDesc::INT8) {
703         for (size_t i = 0; i < n; ++i)
704             dst[i] = T(((const char*)src)[i]);
705         return true;
706     }
707     if (srctype.basetype == TypeDesc::UINT8) {
708         for (size_t i = 0; i < n; ++i)
709             dst[i] = T(((const unsigned char*)src)[i]);
710         return true;
711     }
712     if (srctype.basetype == TypeDesc::INT64) {
713         for (size_t i = 0; i < n; ++i)
714             dst[i] = T(((const long long*)src)[i]);
715         return true;
716     }
717     if (srctype.basetype == TypeDesc::UINT64) {
718         for (size_t i = 0; i < n; ++i)
719             dst[i] = T(((const unsigned long long*)src)[i]);
720         return true;
721     }
722     return false;
723 }
724 
725 }  // namespace
726 
727 
728 
729 bool
convert_type(TypeDesc srctype,const void * src,TypeDesc dsttype,void * dst,int n)730 convert_type(TypeDesc srctype, const void* src, TypeDesc dsttype, void* dst,
731              int n)
732 {
733     if (n > 1) {
734         // Handle multiple values by turning into or expanding array length
735         srctype.arraylen = srctype.numelements() * n;
736         dsttype.arraylen = dsttype.numelements() * n;
737     }
738 
739     if (srctype.basetype == dsttype.basetype
740         && srctype.basevalues() == dsttype.basevalues()) {
741         size_t size = srctype.size();
742         memcpy(dst, src, size);
743         return size;
744     }
745 
746     if (dsttype == TypeString) {
747         (*(ustring*)dst) = ustring(tostring(srctype, src));
748         return true;
749     }
750 
751     if (dsttype.basetype == TypeDesc::INT
752         && dsttype.basevalues() == srctype.basevalues()) {
753         if (to_ints<int>(srctype, src, (int*)dst, dsttype.basevalues()))
754             return true;
755     }
756     if (dsttype == TypeInt && srctype == TypeString) {
757         // Only succeed for a string if it exactly holds something that
758         // excatly parses to an int value.
759         string_view str(((const char**)src)[0]);
760         int val = 0;
761         if (Strutil::parse_int(str, val) && str.empty()) {
762             ((int*)dst)[0] = val;
763             return true;
764         }
765     }
766     if (dsttype.basetype == TypeDesc::UINT
767         && dsttype.basevalues() == srctype.basevalues()) {
768         if (to_ints<uint32_t>(srctype, src, (uint32_t*)dst,
769                               dsttype.basevalues()))
770             return true;
771     }
772     // N.B. No uint inversion from string
773 
774     if (dsttype.basetype == TypeDesc::FLOAT
775         && dsttype.basevalues() == srctype.basevalues()) {
776         if (to_floats<float>(srctype, src, (float*)dst, dsttype.basevalues()))
777             return true;
778     }
779     if (dsttype == TypeFloat && srctype == TypeRational) {
780         int num          = ((const int*)src)[0];
781         int den          = ((const int*)src)[1];
782         ((float*)dst)[0] = den ? float(num) / float(den) : 0.0f;
783         return true;
784     }
785     if (dsttype == TypeFloat && srctype == TypeString) {
786         // Only succeed for a string if it exactly holds something that
787         // excatly parses to a float value.
788         string_view str(((const char**)src)[0]);
789         float val = 0;
790         if (Strutil::parse_float(str, val) && str.empty()) {
791             ((float*)dst)[0] = val;
792             return true;
793         }
794     }
795 
796     if (dsttype.basetype == TypeDesc::DOUBLE
797         && dsttype.basevalues() == srctype.basevalues()) {
798         if (to_floats<double>(srctype, src, (double*)dst, dsttype.basevalues()))
799             return true;
800     }
801     return false;
802 }
803 
804 
805 
806 bool
operator <(const TypeDesc & x) const807 TypeDesc::operator<(const TypeDesc& x) const noexcept
808 {
809     if (basetype != x.basetype)
810         return basetype < x.basetype;
811     if (aggregate != x.aggregate)
812         return aggregate < x.aggregate;
813     if (arraylen != x.arraylen)
814         return arraylen < x.arraylen;
815     if (vecsemantics != x.vecsemantics)
816         return vecsemantics < x.vecsemantics;
817     return false;  // they are equal
818 }
819 
820 
821 
822 TypeDesc::BASETYPE
basetype_merge(TypeDesc at,TypeDesc bt)823 TypeDesc::basetype_merge(TypeDesc at, TypeDesc bt)
824 {
825     BASETYPE a = (BASETYPE)at.basetype;
826     BASETYPE b = (BASETYPE)bt.basetype;
827 
828     // Same type already? done.
829     if (a == b)
830         return a;
831     if (a == UNKNOWN)
832         return b;
833     if (b == UNKNOWN)
834         return a;
835     // Canonicalize so a's size (in bytes) is >= b's size in bytes. This
836     // unclutters remaining cases.
837     if (TypeDesc(a).size() < TypeDesc(b).size())
838         std::swap(a, b);
839     // Double or float trump anything else
840     if (a == DOUBLE || a == FLOAT)
841         return a;
842     if (a == UINT32 && (b == UINT16 || b == UINT8))
843         return a;
844     if (a == INT32 && (b == INT16 || b == UINT16 || b == INT8 || b == UINT8))
845         return a;
846     if ((a == UINT16 || a == HALF) && b == UINT8)
847         return a;
848     if ((a == INT16 || a == HALF) && (b == INT8 || b == UINT8))
849         return a;
850     // Out of common cases. For all remaining edge cases, punt and say that
851     // we prefer float.
852     return FLOAT;
853 }
854 
855 
856 
857 const TypeDesc TypeDesc::TypeFloat(TypeDesc::FLOAT);
858 const TypeDesc TypeDesc::TypeColor(TypeDesc::FLOAT, TypeDesc::VEC3,
859                                    TypeDesc::COLOR);
860 const TypeDesc TypeDesc::TypePoint(TypeDesc::FLOAT, TypeDesc::VEC3,
861                                    TypeDesc::POINT);
862 const TypeDesc TypeDesc::TypeVector(TypeDesc::FLOAT, TypeDesc::VEC3,
863                                     TypeDesc::VECTOR);
864 const TypeDesc TypeDesc::TypeNormal(TypeDesc::FLOAT, TypeDesc::VEC3,
865                                     TypeDesc::NORMAL);
866 const TypeDesc TypeDesc::TypeMatrix33(TypeDesc::FLOAT, TypeDesc::MATRIX33);
867 const TypeDesc TypeDesc::TypeMatrix44(TypeDesc::FLOAT, TypeDesc::MATRIX44);
868 const TypeDesc TypeDesc::TypeMatrix = TypeDesc::TypeMatrix44;
869 const TypeDesc TypeDesc::TypeString(TypeDesc::STRING);
870 const TypeDesc TypeDesc::TypeInt(TypeDesc::INT);
871 const TypeDesc TypeDesc::TypeHalf(TypeDesc::HALF);
872 const TypeDesc TypeDesc::TypeTimeCode(TypeDesc::UINT, TypeDesc::SCALAR,
873                                       TypeDesc::TIMECODE, 2);
874 const TypeDesc TypeDesc::TypeKeyCode(TypeDesc::INT, TypeDesc::SCALAR,
875                                      TypeDesc::KEYCODE, 7);
876 const TypeDesc TypeDesc::TypeFloat4(TypeDesc::FLOAT, TypeDesc::VEC4);
877 const TypeDesc TypeDesc::TypeRational(TypeDesc::INT, TypeDesc::VEC2,
878                                       TypeDesc::RATIONAL);
879 
880 
881 OIIO_NAMESPACE_END
882