64#ifndef TINY_OBJ_LOADER_H_
65#define TINY_OBJ_LOADER_H_
74#if __cplusplus < 201103L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
75#error "tinyobjloader requires C++11 or later. Compile with -std=c++11 or higher."
77#define TINYOBJ_OVERRIDE override
80#pragma clang diagnostic push
81#if __has_warning("-Wzero-as-null-pointer-constant")
82#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
85#pragma clang diagnostic ignored "-Wpadded"
144#ifdef TINYOBJLOADER_USE_DOUBLE
146typedef double real_t;
155 TEXTURE_TYPE_CUBE_TOP,
156 TEXTURE_TYPE_CUBE_BOTTOM,
157 TEXTURE_TYPE_CUBE_FRONT,
158 TEXTURE_TYPE_CUBE_BACK,
159 TEXTURE_TYPE_CUBE_LEFT,
160 TEXTURE_TYPE_CUBE_RIGHT
168 real_t origin_offset[3];
170 real_t turbulence[3];
171 int texture_resolution;
177 real_t bump_multiplier;
180 std::string colorspace;
190 real_t transmittance[3];
200 std::string ambient_texname;
201 std::string diffuse_texname;
202 std::string specular_texname;
203 std::string specular_highlight_texname;
204 std::string bump_texname;
205 std::string displacement_texname;
206 std::string alpha_texname;
207 std::string reflection_texname;
223 real_t clearcoat_thickness;
224 real_t clearcoat_roughness;
226 real_t anisotropy_rotation;
228 std::string roughness_texname;
229 std::string metallic_texname;
230 std::string sheen_texname;
231 std::string emissive_texname;
232 std::string normal_texname;
242 std::map<std::string, std::string> unknown_parameter;
244#ifdef TINY_OBJ_LOADER_PYTHON_BINDING
246 std::array<double, 3> GetDiffuse() {
247 std::array<double, 3> values;
248 values[0] = double(diffuse[0]);
249 values[1] = double(diffuse[1]);
250 values[2] = double(diffuse[2]);
255 std::array<double, 3> GetSpecular() {
256 std::array<double, 3> values;
257 values[0] = double(specular[0]);
258 values[1] = double(specular[1]);
259 values[2] = double(specular[2]);
264 std::array<double, 3> GetTransmittance() {
265 std::array<double, 3> values;
266 values[0] = double(transmittance[0]);
267 values[1] = double(transmittance[1]);
268 values[2] = double(transmittance[2]);
273 std::array<double, 3> GetEmission() {
274 std::array<double, 3> values;
275 values[0] = double(emission[0]);
276 values[1] = double(emission[1]);
277 values[2] = double(emission[2]);
282 std::array<double, 3> GetAmbient() {
283 std::array<double, 3> values;
284 values[0] = double(ambient[0]);
285 values[1] = double(ambient[1]);
286 values[2] = double(ambient[2]);
291 void SetDiffuse(std::array<double, 3> &a) {
292 diffuse[0] = real_t(a[0]);
293 diffuse[1] = real_t(a[1]);
294 diffuse[2] = real_t(a[2]);
297 void SetAmbient(std::array<double, 3> &a) {
298 ambient[0] = real_t(a[0]);
299 ambient[1] = real_t(a[1]);
300 ambient[2] = real_t(a[2]);
303 void SetSpecular(std::array<double, 3> &a) {
304 specular[0] = real_t(a[0]);
305 specular[1] = real_t(a[1]);
306 specular[2] = real_t(a[2]);
309 void SetTransmittance(std::array<double, 3> &a) {
310 transmittance[0] = real_t(a[0]);
311 transmittance[1] = real_t(a[1]);
312 transmittance[2] = real_t(a[2]);
315 std::string GetCustomParameter(
const std::string &key) {
316 std::map<std::string, std::string>::const_iterator it =
317 unknown_parameter.find(key);
319 if (it != unknown_parameter.end()) {
322 return std::string();
331 std::vector<int> intValues;
332 std::vector<real_t> floatValues;
333 std::vector<std::string> stringValues;
345 std::vector<joint_and_weight_t> weightValues;
357 std::vector<index_t> indices;
358 std::vector<unsigned int>
361 std::vector<int> material_ids;
362 std::vector<unsigned int> smoothing_group_ids;
365 std::vector<tag_t> tags;
374 std::vector<index_t> indices;
375 std::vector<int> num_line_vertices;
379 std::vector<index_t> indices;
391 std::vector<real_t> vertices;
394 std::vector<real_t> vertex_weights;
395 std::vector<real_t> normals;
396 std::vector<real_t> texcoords;
400 std::vector<real_t> texcoord_ws;
401 std::vector<real_t> colors;
411 std::vector<skin_weight_t> skin_weights;
418 const std::vector<real_t> &GetVertices()
const {
return vertices; }
420 const std::vector<real_t> &GetVertexWeights()
const {
return vertex_weights; }
425 void (*vertex_cb)(
void *user_data, real_t x, real_t y, real_t z, real_t w);
426 void (*vertex_color_cb)(
void *user_data, real_t x, real_t y, real_t z,
427 real_t r, real_t g, real_t b,
bool has_color);
428 void (*normal_cb)(
void *user_data, real_t x, real_t y, real_t z);
432 void (*texcoord_cb)(
void *user_data, real_t x, real_t y, real_t z);
437 void (*index_cb)(
void *user_data,
index_t *indices,
int num_indices);
441 void (*usemtl_cb)(
void *user_data,
const char *name,
int material_id);
443 void (*mtllib_cb)(
void *user_data,
const material_t *materials,
446 void (*group_cb)(
void *user_data,
const char **names,
int num_names);
447 void (*object_cb)(
void *user_data,
const char *name);
451 vertex_color_cb(NULL),
461class MaterialReader {
464 virtual ~MaterialReader();
466 virtual bool operator()(
const std::string &matId,
467 std::vector<material_t> *materials,
468 std::map<std::string, int> *matMap, std::string *warn,
469 std::string *err) = 0;
475class MaterialFileReader :
public MaterialReader {
478 explicit MaterialFileReader(
const std::string &mtl_basedir)
479 : m_mtlBaseDir(mtl_basedir) {}
480 virtual ~MaterialFileReader() TINYOBJ_OVERRIDE {}
481 virtual bool operator()(
const std::string &matId,
482 std::vector<material_t> *materials,
483 std::map<std::string, int> *matMap, std::string *warn,
484 std::string *err) TINYOBJ_OVERRIDE;
487 std::string m_mtlBaseDir;
493class MaterialStreamReader :
public MaterialReader {
495 explicit MaterialStreamReader(std::istream &inStream)
496 : m_inStream(inStream) {}
497 virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE {}
498 virtual bool operator()(
const std::string &matId,
499 std::vector<material_t> *materials,
500 std::map<std::string, int> *matMap, std::string *warn,
501 std::string *err) TINYOBJ_OVERRIDE;
504 std::istream &m_inStream;
508struct ObjReaderConfig {
514 std::string triangulation_method;
530 : triangulate(true), triangulation_method(
"simple"),
vertex_color(true) {}
538 ObjReader() : valid_(
false) {}
564 bool Valid()
const {
return valid_; }
566 const attrib_t &GetAttrib()
const {
return attrib_; }
568 const std::vector<shape_t> &GetShapes()
const {
return shapes_; }
570 const std::vector<material_t> &GetMaterials()
const {
return materials_; }
575 const std::string &
Warning()
const {
return warning_; }
580 const std::string &
Error()
const {
return error_; }
586 std::vector<shape_t> shapes_;
587 std::vector<material_t> materials_;
589 std::string warning_;
607bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
608 std::vector<material_t> *materials, std::string *warn,
609 std::string *err,
const char *filename,
610 const char *mtl_basedir = NULL,
bool triangulate =
true,
611 bool default_vcols_fallback =
true);
619bool LoadObjWithCallback(std::istream &inStream,
const callback_t &callback,
620 void *user_data = NULL,
621 MaterialReader *readMatFn = NULL,
622 std::string *warn = NULL, std::string *err = NULL);
628bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
629 std::vector<material_t> *materials, std::string *warn,
630 std::string *err, std::istream *inStream,
631 MaterialReader *readMatFn = NULL,
bool triangulate =
true,
632 bool default_vcols_fallback =
true);
635void LoadMtl(std::map<std::string, int> *material_map,
636 std::vector<material_t> *materials, std::istream *inStream,
637 std::string *warning, std::string *err);
647bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt,
648 const char *linebuf);
656#ifdef TINYOBJLOADER_IMPLEMENTATION
670#ifndef WIN32_LEAN_AND_MEAN
671#define WIN32_LEAN_AND_MEAN
679#ifdef TINYOBJLOADER_USE_MMAP
692#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
694#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT
699#pragma clang diagnostic push
700#pragma clang diagnostic ignored "-Weverything"
705#include "mapbox/earcut.hpp"
708#pragma clang diagnostic pop
719static std::wstring UTF8ToWchar(
const std::string &str) {
720 if (str.empty())
return std::wstring();
722 MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
723 static_cast<int>(str.size()), NULL, 0);
724 if (size_needed == 0)
return std::wstring();
725 std::wstring wstr(
static_cast<size_t>(size_needed), L
'\0');
727 MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
728 static_cast<int>(str.size()), &wstr[0], size_needed);
729 if (result == 0)
return std::wstring();
737static std::wstring LongPathW(
const std::wstring &wpath) {
738 const std::wstring kLongPathPrefix = L
"\\\\?\\";
739 const std::wstring kUNCPrefix = L
"\\\\";
740 const std::wstring kLongUNCPathPrefix = L
"\\\\?\\UNC\\";
743 if (wpath.size() >= kLongPathPrefix.size() &&
744 wpath.substr(0, kLongPathPrefix.size()) == kLongPathPrefix) {
749 if (wpath.size() < MAX_PATH) {
755 std::wstring normalized = wpath;
756 for (std::wstring::size_type i = 0; i < normalized.size(); ++i) {
757 if (normalized[i] == L
'/') normalized[i] = L
'\\';
761 if (normalized.size() >= kUNCPrefix.size() &&
762 normalized.substr(0, kUNCPrefix.size()) == kUNCPrefix) {
763 return kLongUNCPathPrefix + normalized.substr(kUNCPrefix.size());
767 if (normalized.size() >= 2 && normalized[1] == L
':') {
768 return kLongPathPrefix + normalized;
780#ifndef TINYOBJLOADER_DISABLE_FAST_FLOAT
786namespace tinyobj_ff {
789template <
typename T, T V>
790struct integral_constant {
791 static const T value = V;
792 typedef T value_type;
793 typedef integral_constant type;
794 operator value_type()
const {
return value; }
796typedef integral_constant<bool, true> true_type;
797typedef integral_constant<bool, false> false_type;
800template <
typename T,
typename U>
struct is_same : false_type {};
801template <
typename T>
struct is_same<T, T> : true_type {};
804template <
bool B,
typename T =
void>
struct enable_if {};
805template <
typename T>
struct enable_if<true, T> {
typedef T type; };
808template <
bool B,
typename T,
typename F>
struct conditional {
typedef T type; };
809template <
typename T,
typename F>
struct conditional<false, T, F> {
typedef F type; };
812template <
typename T>
struct is_integral : false_type {};
813template <>
struct is_integral<bool> : true_type {};
814template <>
struct is_integral<char> : true_type {};
815template <>
struct is_integral<signed char> : true_type {};
816template <>
struct is_integral<unsigned char> : true_type {};
817template <>
struct is_integral<short> : true_type {};
818template <>
struct is_integral<unsigned short> : true_type {};
819template <>
struct is_integral<int> : true_type {};
820template <>
struct is_integral<unsigned int> : true_type {};
821template <>
struct is_integral<long> : true_type {};
822template <>
struct is_integral<unsigned long> : true_type {};
823template <>
struct is_integral<long long> : true_type {};
824template <>
struct is_integral<unsigned long long> : true_type {};
825template <>
struct is_integral<wchar_t> : true_type {};
826template <>
struct is_integral<char16_t> : true_type {};
827template <>
struct is_integral<char32_t> : true_type {};
830template <
typename T>
struct is_signed : integral_constant<bool, T(-1) < T(0)> {};
833template <typename T> struct underlying_type {
834 typedef __underlying_type(T) type;
838enum class ff_errc { ok = 0, invalid_argument = 22, result_out_of_range = 34 };
842inline T min_val(T a, T b) { return (b < a) ? b : a; }
845template <typename InputIt, typename Size, typename OutputIt>
846inline OutputIt copy_n(InputIt first, Size count, OutputIt result) {
847 for (Size i = 0; i < count; ++i) *result++ = *first++;
852template <typename BidirIt1, typename BidirIt2>
853inline BidirIt2 copy_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last) {
854 while (first != last) *(--d_last) = *(--last);
859template <typename ForwardIt, typename T>
860inline void fill(ForwardIt first, ForwardIt last, const T &value) {
861 for (; first != last; ++first) *first = value;
865template <typename It>
866inline typename conditional<true, long long, It>::type
867distance(It first, It last) {
967#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
968#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
971#if __has_include(<version>)
977#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
978#define FASTFLOAT_CONSTEXPR14 constexpr
980#define FASTFLOAT_CONSTEXPR14
983#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
984#define FASTFLOAT_HAS_BIT_CAST 1
986#define FASTFLOAT_HAS_BIT_CAST 0
989#if defined(__cpp_lib_is_constant_evaluated) && \
990 __cpp_lib_is_constant_evaluated >= 201811L
991#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
993#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
996#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
997#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x)
999#define FASTFLOAT_IF_CONSTEXPR17(x) if (x)
1003#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \
1004 defined(__cpp_lib_constexpr_algorithms) && \
1005 __cpp_lib_constexpr_algorithms >= 201806L
1006#define FASTFLOAT_CONSTEXPR20 constexpr
1007#define FASTFLOAT_IS_CONSTEXPR 1
1009#define FASTFLOAT_CONSTEXPR20
1010#define FASTFLOAT_IS_CONSTEXPR 0
1013#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
1014#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0
1016#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1
1021#ifndef FASTFLOAT_FLOAT_COMMON_H
1022#define FASTFLOAT_FLOAT_COMMON_H
1028#if __has_include(<stdfloat>) && (__cplusplus > 202002L || (defined(_MSVC_LANG) && (_MSVC_LANG > 202002L)))
1033#define FASTFLOAT_VERSION_MAJOR 8
1034#define FASTFLOAT_VERSION_MINOR 0
1035#define FASTFLOAT_VERSION_PATCH 2
1037#define FASTFLOAT_STRINGIZE_IMPL(x) #x
1038#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
1040#define FASTFLOAT_VERSION_STR \
1041 FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MAJOR) \
1042 "." FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MINOR) "." FASTFLOAT_STRINGIZE( \
1043 FASTFLOAT_VERSION_PATCH)
1045#define FASTFLOAT_VERSION \
1046 (FASTFLOAT_VERSION_MAJOR * 10000 + FASTFLOAT_VERSION_MINOR * 100 + \
1047 FASTFLOAT_VERSION_PATCH)
1049namespace fast_float {
1051enum class chars_format : uint64_t;
1054constexpr chars_format basic_json_fmt = chars_format(1 << 5);
1055constexpr chars_format basic_fortran_fmt = chars_format(1 << 6);
1058enum class chars_format : uint64_t {
1059 scientific = 1 << 0,
1064 json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan,
1066 json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific,
1067 fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific,
1068 general = fixed | scientific,
1069 allow_leading_plus = 1 << 7,
1070 skip_white_space = 1 << 8,
1073template <
typename UC>
struct from_chars_result_t {
1075 tinyobj_ff::ff_errc ec;
1078using from_chars_result = from_chars_result_t<char>;
1080template <
typename UC>
struct parse_options_t {
1081 constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
1082 UC dot = UC(
'.'),
int b = 10)
1083 : format(fmt), decimal_point(dot), base(b) {}
1086 chars_format format;
1093using parse_options = parse_options_t<char>;
1097#if FASTFLOAT_HAS_BIT_CAST
1101#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
1102 defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \
1103 defined(__MINGW64__) || defined(__s390x__) || \
1104 (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
1105 defined(__PPC64LE__)) || \
1106 defined(__loongarch64))
1107#define FASTFLOAT_64BIT 1
1108#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
1109 defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \
1110 defined(__MINGW32__) || defined(__EMSCRIPTEN__))
1111#define FASTFLOAT_32BIT 1
1117#if SIZE_MAX == 0xffff
1118#error Unknown platform (16-bit, unsupported)
1119#elif SIZE_MAX == 0xffffffff
1120#define FASTFLOAT_32BIT 1
1121#elif SIZE_MAX == 0xffffffffffffffff
1122#define FASTFLOAT_64BIT 1
1124#error Unknown platform (not 32-bit, not 64-bit?)
1128#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) || \
1129 (defined(_M_ARM64) && !defined(__MINGW32__))
1133#if defined(_MSC_VER) && !defined(__clang__)
1134#define FASTFLOAT_VISUAL_STUDIO 1
1137#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
1138#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
1140#define FASTFLOAT_IS_BIG_ENDIAN 0
1142#if defined(__APPLE__) || defined(__FreeBSD__)
1143#include <machine/endian.h>
1144#elif defined(sun) || defined(__sun)
1145#include <sys/byteorder.h>
1146#elif defined(__MVS__)
1147#include <sys/endian.h>
1150#if __has_include(<endian.h>)
1156#ifndef __BYTE_ORDER__
1158#define FASTFLOAT_IS_BIG_ENDIAN 0
1161#ifndef __ORDER_LITTLE_ENDIAN__
1163#define FASTFLOAT_IS_BIG_ENDIAN 0
1166#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1167#define FASTFLOAT_IS_BIG_ENDIAN 0
1169#define FASTFLOAT_IS_BIG_ENDIAN 1
1173#if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \
1174 (defined(_M_AMD64) || defined(_M_X64) || \
1175 (defined(_M_IX86_FP) && _M_IX86_FP == 2)))
1176#define FASTFLOAT_SSE2 1
1179#if defined(__aarch64__) || defined(_M_ARM64)
1180#define FASTFLOAT_NEON 1
1183#if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON)
1184#define FASTFLOAT_HAS_SIMD 1
1187#if defined(__GNUC__)
1189#define FASTFLOAT_SIMD_DISABLE_WARNINGS \
1190 _Pragma("GCC diagnostic push") \
1191 _Pragma("GCC diagnostic ignored \"-Wcast-align\"")
1193#define FASTFLOAT_SIMD_DISABLE_WARNINGS
1196#if defined(__GNUC__)
1197#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
1199#define FASTFLOAT_SIMD_RESTORE_WARNINGS
1202#ifdef FASTFLOAT_VISUAL_STUDIO
1203#define fastfloat_really_inline __forceinline
1205#define fastfloat_really_inline inline __attribute__((always_inline))
1208#ifndef FASTFLOAT_ASSERT
1209#define FASTFLOAT_ASSERT(x) \
1213#ifndef FASTFLOAT_DEBUG_ASSERT
1214#define FASTFLOAT_DEBUG_ASSERT(x) \
1219#define FASTFLOAT_TRY(x) \
1225#define FASTFLOAT_ENABLE_IF(...) \
1226 typename tinyobj_ff::enable_if<(__VA_ARGS__), int>::type
1228namespace fast_float {
1230fastfloat_really_inline
constexpr bool cpp20_and_in_constexpr() {
1231#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
1232 return std::is_constant_evaluated();
1238template <
typename T>
1239struct is_supported_float_type
1240 : tinyobj_ff::integral_constant<
1241 bool, tinyobj_ff::is_same<T, double>::value || tinyobj_ff::is_same<T, float>::value
1242#ifdef __STDCPP_FLOAT64_T__
1243 || tinyobj_ff::is_same<T, std::float64_t>::value
1245#ifdef __STDCPP_FLOAT32_T__
1246 || tinyobj_ff::is_same<T, std::float32_t>::value
1248#ifdef __STDCPP_FLOAT16_T__
1249 || tinyobj_ff::is_same<T, std::float16_t>::value
1251#ifdef __STDCPP_BFLOAT16_T__
1252 || tinyobj_ff::is_same<T, std::bfloat16_t>::value
1257template <
typename T>
1258using equiv_uint_t =
typename tinyobj_ff::conditional<
1259 sizeof(T) == 1, uint8_t,
1260 typename tinyobj_ff::conditional<
1261 sizeof(T) == 2, uint16_t,
1262 typename tinyobj_ff::conditional<
sizeof(T) == 4, uint32_t,
1263 uint64_t>::type>::type>::type;
1265template <
typename T>
struct is_supported_integer_type : tinyobj_ff::is_integral<T> {};
1267template <
typename UC>
1268struct is_supported_char_type
1269 : tinyobj_ff::integral_constant<bool, tinyobj_ff::is_same<UC, char>::value ||
1270 tinyobj_ff::is_same<UC, wchar_t>::value ||
1271 tinyobj_ff::is_same<UC, char16_t>::value ||
1272 tinyobj_ff::is_same<UC, char32_t>::value
1274 || tinyobj_ff::is_same<UC, char8_t>::value
1280template <
typename UC>
1281inline FASTFLOAT_CONSTEXPR14
bool
1282fastfloat_strncasecmp(UC
const *actual_mixedcase, UC
const *expected_lowercase,
1284 for (
size_t i = 0; i < length; ++i) {
1285 UC
const actual = actual_mixedcase[i];
1286 if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
1293#ifndef FLT_EVAL_METHOD
1294#error "FLT_EVAL_METHOD should be defined, please include cfloat."
1298template <
typename T>
struct span {
1302 constexpr span(T
const *_ptr,
size_t _length) : ptr(_ptr), length(_length) {}
1304 constexpr span() : ptr(nullptr), length(0) {}
1306 constexpr size_t len() const noexcept {
return length; }
1308 FASTFLOAT_CONSTEXPR14
const T &operator[](
size_t index)
const noexcept {
1309 FASTFLOAT_DEBUG_ASSERT(index < length);
1318 constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
1320 constexpr value128() : low(0), high(0) {}
1324fastfloat_really_inline FASTFLOAT_CONSTEXPR14
int
1325leading_zeroes_generic(uint64_t input_num,
int last_bit = 0) {
1326 if (input_num & uint64_t(0xffffffff00000000)) {
1330 if (input_num & uint64_t(0xffff0000)) {
1334 if (input_num & uint64_t(0xff00)) {
1338 if (input_num & uint64_t(0xf0)) {
1342 if (input_num & uint64_t(0xc)) {
1346 if (input_num & uint64_t(0x2)) {
1349 return 63 - last_bit;
1353fastfloat_really_inline FASTFLOAT_CONSTEXPR20
int
1354leading_zeroes(uint64_t input_num) {
1355 assert(input_num > 0);
1356 if (cpp20_and_in_constexpr()) {
1357 return leading_zeroes_generic(input_num);
1359#ifdef FASTFLOAT_VISUAL_STUDIO
1360#if defined(_M_X64) || defined(_M_ARM64)
1361 unsigned long leading_zero = 0;
1364 _BitScanReverse64(&leading_zero, input_num);
1365 return (
int)(63 - leading_zero);
1367 return leading_zeroes_generic(input_num);
1370 return __builtin_clzll(input_num);
1375fastfloat_really_inline
constexpr uint64_t emulu(uint32_t x, uint32_t y) {
1376 return x * (uint64_t)y;
1379fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
1380umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
1381 uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
1382 uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
1383 uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
1384 uint64_t adbc_carry = (uint64_t)(adbc < ad);
1385 uint64_t lo = bd + (adbc << 32);
1386 *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
1387 (adbc_carry << 32) + (uint64_t)(lo < bd);
1391#ifdef FASTFLOAT_32BIT
1394#if !defined(__MINGW64__)
1395fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab,
1398 return umul128_generic(ab, cd, hi);
1405fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
1406full_multiplication(uint64_t a, uint64_t b) {
1407 if (cpp20_and_in_constexpr()) {
1409 answer.low = umul128_generic(a, b, &answer.high);
1413#if defined(_M_ARM64) && !defined(__MINGW32__)
1416 answer.high = __umulh(a, b);
1418#elif defined(FASTFLOAT_32BIT) || \
1419 (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64))
1420 answer.low = _umul128(a, b, &answer.high);
1421#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
1422 __uint128_t r = ((__uint128_t)a) * b;
1423 answer.low = uint64_t(r);
1424 answer.high = uint64_t(r >> 64);
1426 answer.low = umul128_generic(a, b, &answer.high);
1431struct adjusted_mantissa {
1432 uint64_t mantissa{0};
1434 adjusted_mantissa() =
default;
1436 constexpr bool operator==(adjusted_mantissa
const &o)
const {
1437 return mantissa == o.mantissa && power2 == o.power2;
1440 constexpr bool operator!=(adjusted_mantissa
const &o)
const {
1441 return mantissa != o.mantissa || power2 != o.power2;
1446constexpr static int32_t invalid_am_bias = -0x8000;
1449constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
1451template <
typename T,
typename U =
void>
struct binary_format_lookup_tables;
1453template <
typename T>
struct binary_format : binary_format_lookup_tables<T> {
1454 using equiv_uint = equiv_uint_t<T>;
1456 static constexpr int mantissa_explicit_bits();
1457 static constexpr int minimum_exponent();
1458 static constexpr int infinite_power();
1459 static constexpr int sign_index();
1460 static constexpr int
1461 min_exponent_fast_path();
1462 static constexpr int max_exponent_fast_path();
1463 static constexpr int max_exponent_round_to_even();
1464 static constexpr int min_exponent_round_to_even();
1465 static constexpr uint64_t max_mantissa_fast_path(int64_t power);
1466 static constexpr uint64_t
1467 max_mantissa_fast_path();
1468 static constexpr int largest_power_of_ten();
1469 static constexpr int smallest_power_of_ten();
1470 static constexpr T exact_power_of_ten(int64_t power);
1471 static constexpr size_t max_digits();
1472 static constexpr equiv_uint exponent_mask();
1473 static constexpr equiv_uint mantissa_mask();
1474 static constexpr equiv_uint hidden_bit_mask();
1477template <
typename U>
struct binary_format_lookup_tables<double, U> {
1478 static constexpr double powers_of_ten[] = {
1479 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
1480 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
1484 static constexpr uint64_t max_mantissa[] = {
1486 0x20000000000000 / 5,
1487 0x20000000000000 / (5 * 5),
1488 0x20000000000000 / (5 * 5 * 5),
1489 0x20000000000000 / (5 * 5 * 5 * 5),
1490 0x20000000000000 / (constant_55555),
1491 0x20000000000000 / (constant_55555 * 5),
1492 0x20000000000000 / (constant_55555 * 5 * 5),
1493 0x20000000000000 / (constant_55555 * 5 * 5 * 5),
1494 0x20000000000000 / (constant_55555 * 5 * 5 * 5 * 5),
1495 0x20000000000000 / (constant_55555 * constant_55555),
1496 0x20000000000000 / (constant_55555 * constant_55555 * 5),
1497 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5),
1498 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5),
1499 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555),
1500 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5),
1502 (constant_55555 * constant_55555 * constant_55555 * 5 * 5),
1504 (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
1506 (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5),
1508 (constant_55555 * constant_55555 * constant_55555 * constant_55555),
1509 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 *
1510 constant_55555 * 5),
1511 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 *
1512 constant_55555 * 5 * 5),
1513 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 *
1514 constant_55555 * 5 * 5 * 5),
1515 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 *
1516 constant_55555 * 5 * 5 * 5 * 5)};
1519#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1521template <
typename U>
1522constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[];
1524template <
typename U>
1525constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[];
1529template <
typename U>
struct binary_format_lookup_tables<float, U> {
1530 static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f,
1531 1e6f, 1e7f, 1e8f, 1e9f, 1e10f};
1535 static constexpr uint64_t max_mantissa[] = {
1538 0x1000000 / (5 * 5),
1539 0x1000000 / (5 * 5 * 5),
1540 0x1000000 / (5 * 5 * 5 * 5),
1541 0x1000000 / (constant_55555),
1542 0x1000000 / (constant_55555 * 5),
1543 0x1000000 / (constant_55555 * 5 * 5),
1544 0x1000000 / (constant_55555 * 5 * 5 * 5),
1545 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5),
1546 0x1000000 / (constant_55555 * constant_55555),
1547 0x1000000 / (constant_55555 * constant_55555 * 5)};
1550#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1552template <
typename U>
1553constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[];
1555template <
typename U>
1556constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[];
1561inline constexpr int binary_format<double>::min_exponent_fast_path() {
1562#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
1570inline constexpr int binary_format<float>::min_exponent_fast_path() {
1571#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
1579inline constexpr int binary_format<double>::mantissa_explicit_bits() {
1584inline constexpr int binary_format<float>::mantissa_explicit_bits() {
1589inline constexpr int binary_format<double>::max_exponent_round_to_even() {
1594inline constexpr int binary_format<float>::max_exponent_round_to_even() {
1599inline constexpr int binary_format<double>::min_exponent_round_to_even() {
1604inline constexpr int binary_format<float>::min_exponent_round_to_even() {
1608template <>
inline constexpr int binary_format<double>::minimum_exponent() {
1612template <>
inline constexpr int binary_format<float>::minimum_exponent() {
1616template <>
inline constexpr int binary_format<double>::infinite_power() {
1620template <>
inline constexpr int binary_format<float>::infinite_power() {
1624template <>
inline constexpr int binary_format<double>::sign_index() {
1628template <>
inline constexpr int binary_format<float>::sign_index() {
1633inline constexpr int binary_format<double>::max_exponent_fast_path() {
1638inline constexpr int binary_format<float>::max_exponent_fast_path() {
1643inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
1644 return uint64_t(2) << mantissa_explicit_bits();
1648inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
1649 return uint64_t(2) << mantissa_explicit_bits();
1653#ifdef __STDCPP_FLOAT16_T__
1654template <
typename U>
struct binary_format_lookup_tables<std::float16_t, U> {
1655 static constexpr std::float16_t powers_of_ten[] = {1e0f16, 1e1f16, 1e2f16,
1660 static constexpr uint64_t max_mantissa[] = {0x800,
1663 0x800 / (5 * 5 * 5),
1664 0x800 / (5 * 5 * 5 * 5),
1665 0x800 / (constant_55555)};
1668#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1670template <
typename U>
1671constexpr std::float16_t
1672 binary_format_lookup_tables<std::float16_t, U>::powers_of_ten[];
1674template <
typename U>
1676 binary_format_lookup_tables<std::float16_t, U>::max_mantissa[];
1681inline constexpr std::float16_t
1682binary_format<std::float16_t>::exact_power_of_ten(int64_t power) {
1684 return (
void)powers_of_ten[0], powers_of_ten[power];
1688inline constexpr binary_format<std::float16_t>::equiv_uint
1689binary_format<std::float16_t>::exponent_mask() {
1694inline constexpr binary_format<std::float16_t>::equiv_uint
1695binary_format<std::float16_t>::mantissa_mask() {
1700inline constexpr binary_format<std::float16_t>::equiv_uint
1701binary_format<std::float16_t>::hidden_bit_mask() {
1706inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() {
1711inline constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() {
1716inline constexpr uint64_t
1717binary_format<std::float16_t>::max_mantissa_fast_path() {
1718 return uint64_t(2) << mantissa_explicit_bits();
1722inline constexpr uint64_t
1723binary_format<std::float16_t>::max_mantissa_fast_path(int64_t power) {
1728 return (
void)max_mantissa[0], max_mantissa[power];
1732inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() {
1738binary_format<std::float16_t>::max_exponent_round_to_even() {
1744binary_format<std::float16_t>::min_exponent_round_to_even() {
1749inline constexpr int binary_format<std::float16_t>::minimum_exponent() {
1754inline constexpr int binary_format<std::float16_t>::infinite_power() {
1758template <>
inline constexpr int binary_format<std::float16_t>::sign_index() {
1763inline constexpr int binary_format<std::float16_t>::largest_power_of_ten() {
1768inline constexpr int binary_format<std::float16_t>::smallest_power_of_ten() {
1773inline constexpr size_t binary_format<std::float16_t>::max_digits() {
1779#ifdef __STDCPP_BFLOAT16_T__
1780template <
typename U>
struct binary_format_lookup_tables<std::bfloat16_t, U> {
1781 static constexpr std::bfloat16_t powers_of_ten[] = {1e0bf16, 1e1bf16, 1e2bf16,
1786 static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5),
1787 0x100 / (5 * 5 * 5),
1788 0x100 / (5 * 5 * 5 * 5)};
1791#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1793template <
typename U>
1794constexpr std::bfloat16_t
1795 binary_format_lookup_tables<std::bfloat16_t, U>::powers_of_ten[];
1797template <
typename U>
1799 binary_format_lookup_tables<std::bfloat16_t, U>::max_mantissa[];
1804inline constexpr std::bfloat16_t
1805binary_format<std::bfloat16_t>::exact_power_of_ten(int64_t power) {
1807 return (
void)powers_of_ten[0], powers_of_ten[power];
1811inline constexpr int binary_format<std::bfloat16_t>::max_exponent_fast_path() {
1816inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1817binary_format<std::bfloat16_t>::exponent_mask() {
1822inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1823binary_format<std::bfloat16_t>::mantissa_mask() {
1828inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1829binary_format<std::bfloat16_t>::hidden_bit_mask() {
1834inline constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
1839inline constexpr uint64_t
1840binary_format<std::bfloat16_t>::max_mantissa_fast_path() {
1841 return uint64_t(2) << mantissa_explicit_bits();
1845inline constexpr uint64_t
1846binary_format<std::bfloat16_t>::max_mantissa_fast_path(int64_t power) {
1851 return (
void)max_mantissa[0], max_mantissa[power];
1855inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() {
1861binary_format<std::bfloat16_t>::max_exponent_round_to_even() {
1867binary_format<std::bfloat16_t>::min_exponent_round_to_even() {
1872inline constexpr int binary_format<std::bfloat16_t>::minimum_exponent() {
1877inline constexpr int binary_format<std::bfloat16_t>::infinite_power() {
1881template <>
inline constexpr int binary_format<std::bfloat16_t>::sign_index() {
1886inline constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() {
1891inline constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() {
1896inline constexpr size_t binary_format<std::bfloat16_t>::max_digits() {
1902inline constexpr uint64_t
1903binary_format<double>::max_mantissa_fast_path(int64_t power) {
1908 return (
void)max_mantissa[0], max_mantissa[power];
1912inline constexpr uint64_t
1913binary_format<float>::max_mantissa_fast_path(int64_t power) {
1918 return (
void)max_mantissa[0], max_mantissa[power];
1922inline constexpr double
1923binary_format<double>::exact_power_of_ten(int64_t power) {
1925 return (
void)powers_of_ten[0], powers_of_ten[power];
1929inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
1931 return (
void)powers_of_ten[0], powers_of_ten[power];
1934template <>
inline constexpr int binary_format<double>::largest_power_of_ten() {
1938template <>
inline constexpr int binary_format<float>::largest_power_of_ten() {
1943inline constexpr int binary_format<double>::smallest_power_of_ten() {
1947template <>
inline constexpr int binary_format<float>::smallest_power_of_ten() {
1951template <>
inline constexpr size_t binary_format<double>::max_digits() {
1955template <>
inline constexpr size_t binary_format<float>::max_digits() {
1960inline constexpr binary_format<float>::equiv_uint
1961binary_format<float>::exponent_mask() {
1966inline constexpr binary_format<double>::equiv_uint
1967binary_format<double>::exponent_mask() {
1968 return 0x7FF0000000000000;
1972inline constexpr binary_format<float>::equiv_uint
1973binary_format<float>::mantissa_mask() {
1978inline constexpr binary_format<double>::equiv_uint
1979binary_format<double>::mantissa_mask() {
1980 return 0x000FFFFFFFFFFFFF;
1984inline constexpr binary_format<float>::equiv_uint
1985binary_format<float>::hidden_bit_mask() {
1990inline constexpr binary_format<double>::equiv_uint
1991binary_format<double>::hidden_bit_mask() {
1992 return 0x0010000000000000;
1995template <
typename T>
1996fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
1997to_float(
bool negative, adjusted_mantissa am, T &value) {
1998 using equiv_uint = equiv_uint_t<T>;
1999 equiv_uint word = equiv_uint(am.mantissa);
2000 word = equiv_uint(word | equiv_uint(am.power2)
2001 << binary_format<T>::mantissa_explicit_bits());
2003 equiv_uint(word | equiv_uint(negative) << binary_format<T>::sign_index());
2004#if FASTFLOAT_HAS_BIT_CAST
2005 value = std::bit_cast<T>(word);
2007 ::memcpy(&value, &word,
sizeof(T));
2011template <
typename =
void>
struct space_lut {
2012 static constexpr bool value[] = {
2013 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2014 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2015 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2016 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2017 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2018 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2019 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2020 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2021 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2022 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2023 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2026#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
2028template <
typename T>
constexpr bool space_lut<T>::value[];
2032template <
typename UC>
constexpr bool is_space(UC c) {
2033 return c < 256 && space_lut<>::value[uint8_t(c)];
2036template <
typename UC>
static constexpr uint64_t int_cmp_zeros() {
2037 static_assert((
sizeof(UC) == 1) || (
sizeof(UC) == 2) || (
sizeof(UC) == 4),
2038 "Unsupported character size");
2039 return (
sizeof(UC) == 1) ? 0x3030303030303030
2041 ? (uint64_t(UC(
'0')) << 48 | uint64_t(UC(
'0')) << 32 |
2042 uint64_t(UC(
'0')) << 16 | UC(
'0'))
2043 : (uint64_t(UC(
'0')) << 32 | UC(
'0'));
2046template <
typename UC>
static constexpr int int_cmp_len() {
2047 return sizeof(uint64_t) /
sizeof(UC);
2050template <
typename UC>
constexpr UC
const *str_const_nan();
2052template <>
constexpr char const *str_const_nan<char>() {
return "nan"; }
2054template <>
constexpr wchar_t const *str_const_nan<wchar_t>() {
return L
"nan"; }
2056template <>
constexpr char16_t const *str_const_nan<char16_t>() {
2060template <>
constexpr char32_t const *str_const_nan<char32_t>() {
2065template <>
constexpr char8_t const *str_const_nan<char8_t>() {
2070template <
typename UC>
constexpr UC
const *str_const_inf();
2072template <>
constexpr char const *str_const_inf<char>() {
return "infinity"; }
2074template <>
constexpr wchar_t const *str_const_inf<wchar_t>() {
2078template <>
constexpr char16_t const *str_const_inf<char16_t>() {
2082template <>
constexpr char32_t const *str_const_inf<char32_t>() {
2087template <>
constexpr char8_t const *str_const_inf<char8_t>() {
2088 return u8
"infinity";
2092template <
typename =
void>
struct int_luts {
2093 static constexpr uint8_t chdigit[] = {
2094 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2095 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2096 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2097 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255,
2098 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
2099 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
2100 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17,
2101 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
2102 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2103 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2104 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2105 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2106 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2107 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2108 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2109 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2110 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2113 static constexpr size_t maxdigits_u64[] = {
2114 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16,
2115 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13};
2117 static constexpr uint64_t min_safe_u64[] = {
2118 9223372036854775808ull, 12157665459056928801ull, 4611686018427387904,
2119 7450580596923828125, 4738381338321616896, 3909821048582988049,
2120 9223372036854775808ull, 12157665459056928801ull, 10000000000000000000ull,
2121 5559917313492231481, 2218611106740436992, 8650415919381337933,
2122 2177953337809371136, 6568408355712890625, 1152921504606846976,
2123 2862423051509815793, 6746640616477458432, 15181127029874798299ull,
2124 1638400000000000000, 3243919932521508681, 6221821273427820544,
2125 11592836324538749809ull, 876488338465357824, 1490116119384765625,
2126 2481152873203736576, 4052555153018976267, 6502111422497947648,
2127 10260628712958602189ull, 15943230000000000000ull, 787662783788549761,
2128 1152921504606846976, 1667889514952984961, 2386420683693101056,
2129 3379220508056640625, 4738381338321616896};
2132#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
2134template <
typename T>
constexpr uint8_t int_luts<T>::chdigit[];
2136template <
typename T>
constexpr size_t int_luts<T>::maxdigits_u64[];
2138template <
typename T>
constexpr uint64_t int_luts<T>::min_safe_u64[];
2142template <
typename UC>
2143fastfloat_really_inline
constexpr uint8_t ch_to_digit(UC c) {
2144 return int_luts<>::chdigit[
static_cast<unsigned char>(c)];
2147fastfloat_really_inline
constexpr size_t max_digits_u64(
int base) {
2148 return int_luts<>::maxdigits_u64[base - 2];
2153fastfloat_really_inline
constexpr uint64_t min_safe_u64(
int base) {
2154 return int_luts<>::min_safe_u64[base - 2];
2157static_assert(tinyobj_ff::is_same<equiv_uint_t<double>, uint64_t>::value,
2158 "equiv_uint should be uint64_t for double");
2159static_assert(std::numeric_limits<double>::is_iec559,
2160 "double must fulfill the requirements of IEC 559 (IEEE 754)");
2162static_assert(tinyobj_ff::is_same<equiv_uint_t<float>, uint32_t>::value,
2163 "equiv_uint should be uint32_t for float");
2164static_assert(std::numeric_limits<float>::is_iec559,
2165 "float must fulfill the requirements of IEC 559 (IEEE 754)");
2167#ifdef __STDCPP_FLOAT64_T__
2168static_assert(tinyobj_ff::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
2169 "equiv_uint should be uint64_t for std::float64_t");
2171 std::numeric_limits<std::float64_t>::is_iec559,
2172 "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)");
2175#ifdef __STDCPP_FLOAT32_T__
2176static_assert(tinyobj_ff::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
2177 "equiv_uint should be uint32_t for std::float32_t");
2179 std::numeric_limits<std::float32_t>::is_iec559,
2180 "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)");
2183#ifdef __STDCPP_FLOAT16_T__
2185 tinyobj_ff::is_same<binary_format<std::float16_t>::equiv_uint, uint16_t>::value,
2186 "equiv_uint should be uint16_t for std::float16_t");
2188 std::numeric_limits<std::float16_t>::is_iec559,
2189 "std::float16_t must fulfill the requirements of IEC 559 (IEEE 754)");
2192#ifdef __STDCPP_BFLOAT16_T__
2194 tinyobj_ff::is_same<binary_format<std::bfloat16_t>::equiv_uint, uint16_t>::value,
2195 "equiv_uint should be uint16_t for std::bfloat16_t");
2197 std::numeric_limits<std::bfloat16_t>::is_iec559,
2198 "std::bfloat16_t must fulfill the requirements of IEC 559 (IEEE 754)");
2201constexpr chars_format operator~(chars_format rhs)
noexcept {
2202 using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2203 return static_cast<chars_format
>(~static_cast<int_type>(rhs));
2206constexpr chars_format operator&(chars_format lhs, chars_format rhs)
noexcept {
2207 using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2208 return static_cast<chars_format
>(
static_cast<int_type
>(lhs) &
2209 static_cast<int_type
>(rhs));
2212constexpr chars_format operator|(chars_format lhs, chars_format rhs)
noexcept {
2213 using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2214 return static_cast<chars_format
>(
static_cast<int_type
>(lhs) |
2215 static_cast<int_type
>(rhs));
2218constexpr chars_format operator^(chars_format lhs, chars_format rhs)
noexcept {
2219 using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2220 return static_cast<chars_format
>(
static_cast<int_type
>(lhs) ^
2221 static_cast<int_type
>(rhs));
2224fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2225operator&=(chars_format &lhs, chars_format rhs)
noexcept {
2226 return lhs = (lhs & rhs);
2229fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2230operator|=(chars_format &lhs, chars_format rhs)
noexcept {
2231 return lhs = (lhs | rhs);
2234fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2235operator^=(chars_format &lhs, chars_format rhs)
noexcept {
2236 return lhs = (lhs ^ rhs);
2241constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
2243#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS
2244 | chars_format::allow_leading_plus
2246#ifdef FASTFLOAT_SKIP_WHITE_SPACE
2247 | chars_format::skip_white_space
2258#ifndef FASTFLOAT_FAST_FLOAT_H
2259#define FASTFLOAT_FAST_FLOAT_H
2262namespace fast_float {
2288template <
typename T,
typename UC = char,
2289 typename = FASTFLOAT_ENABLE_IF(is_supported_float_type<T>::value)>
2290FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2291from_chars(UC
const *first, UC
const *last, T &value,
2292 chars_format fmt = chars_format::general)
noexcept;
2298template <
typename T,
typename UC =
char>
2299FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2300from_chars_advanced(UC
const *first, UC
const *last, T &value,
2301 parse_options_t<UC> options)
noexcept;
2306template <
typename T,
typename UC = char,
2307 typename = FASTFLOAT_ENABLE_IF(is_supported_integer_type<T>::value)>
2308FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2309from_chars(UC
const *first, UC
const *last, T &value,
int base = 10) noexcept;
2315#ifndef FASTFLOAT_ASCII_NUMBER_H
2316#define FASTFLOAT_ASCII_NUMBER_H
2323#ifdef FASTFLOAT_SSE2
2324#include <emmintrin.h>
2327#ifdef FASTFLOAT_NEON
2328#include <arm_neon.h>
2331namespace fast_float {
2333template <
typename UC> fastfloat_really_inline
constexpr bool has_simd_opt() {
2334#ifdef FASTFLOAT_HAS_SIMD
2335 return tinyobj_ff::is_same<UC, char16_t>::value;
2343template <
typename UC>
2344fastfloat_really_inline
constexpr bool is_integer(UC c)
noexcept {
2345 return !(c > UC(
'9') || c < UC(
'0'));
2348fastfloat_really_inline
constexpr uint64_t byteswap(uint64_t val) {
2349 return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 |
2350 (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 |
2351 (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 |
2352 (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56;
2356template <
typename UC>
2357fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
2358read8_to_u64(UC
const *chars) {
2359 if (cpp20_and_in_constexpr() || !tinyobj_ff::is_same<UC, char>::value) {
2361 for (
int i = 0; i < 8; ++i) {
2362 val |= uint64_t(uint8_t(*chars)) << (i * 8);
2368 ::memcpy(&val, chars,
sizeof(uint64_t));
2369#if FASTFLOAT_IS_BIG_ENDIAN == 1
2371 val = byteswap(val);
2376#ifdef FASTFLOAT_SSE2
2378fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i
const data) {
2379 FASTFLOAT_SIMD_DISABLE_WARNINGS
2380 __m128i
const packed = _mm_packus_epi16(data, data);
2381#ifdef FASTFLOAT_64BIT
2382 return uint64_t(_mm_cvtsi128_si64(packed));
2386 _mm_storel_epi64(
reinterpret_cast<__m128i *
>(&value), packed);
2389 FASTFLOAT_SIMD_RESTORE_WARNINGS
2392fastfloat_really_inline uint64_t simd_read8_to_u64(
char16_t const *chars) {
2393 FASTFLOAT_SIMD_DISABLE_WARNINGS
2394 return simd_read8_to_u64(
2395 _mm_loadu_si128(
reinterpret_cast<__m128i
const *
>(chars)));
2396 FASTFLOAT_SIMD_RESTORE_WARNINGS
2399#elif defined(FASTFLOAT_NEON)
2401fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t
const data) {
2402 FASTFLOAT_SIMD_DISABLE_WARNINGS
2403 uint8x8_t utf8_packed = vmovn_u16(data);
2404 return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0);
2405 FASTFLOAT_SIMD_RESTORE_WARNINGS
2408fastfloat_really_inline uint64_t simd_read8_to_u64(
char16_t const *chars) {
2409 FASTFLOAT_SIMD_DISABLE_WARNINGS
2410 return simd_read8_to_u64(
2411 vld1q_u16(
reinterpret_cast<uint16_t
const *
>(chars)));
2412 FASTFLOAT_SIMD_RESTORE_WARNINGS
2418#if defined(_MSC_VER) && _MSC_VER <= 1900
2419template <
typename UC>
2421template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
2424uint64_t simd_read8_to_u64(UC
const *) {
2429fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
2430parse_eight_digits_unrolled(uint64_t val) {
2431 uint64_t
const mask = 0x000000FF000000FF;
2432 uint64_t
const mul1 = 0x000F424000000064;
2433 uint64_t
const mul2 = 0x0000271000000001;
2434 val -= 0x3030303030303030;
2435 val = (val * 10) + (val >> 8);
2436 val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
2437 return uint32_t(val);
2441template <
typename UC>
2442fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
2443parse_eight_digits_unrolled(UC
const *chars)
noexcept {
2444 if (cpp20_and_in_constexpr() || !has_simd_opt<UC>()) {
2445 return parse_eight_digits_unrolled(read8_to_u64(chars));
2447 return parse_eight_digits_unrolled(simd_read8_to_u64(chars));
2451fastfloat_really_inline
constexpr bool
2452is_made_of_eight_digits_fast(uint64_t val)
noexcept {
2453 return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
2454 0x8080808080808080));
2457#ifdef FASTFLOAT_HAS_SIMD
2462fastfloat_really_inline FASTFLOAT_CONSTEXPR20
bool
2463simd_parse_if_eight_digits_unrolled(
char16_t const *chars,
2464 uint64_t &i)
noexcept {
2465 if (cpp20_and_in_constexpr()) {
2468#ifdef FASTFLOAT_SSE2
2469 FASTFLOAT_SIMD_DISABLE_WARNINGS
2470 __m128i
const data =
2471 _mm_loadu_si128(
reinterpret_cast<__m128i
const *
>(chars));
2475 __m128i
const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720));
2476 __m128i
const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759));
2478 if (_mm_movemask_epi8(t1) == 0) {
2479 i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
2483 FASTFLOAT_SIMD_RESTORE_WARNINGS
2484#elif defined(FASTFLOAT_NEON)
2485 FASTFLOAT_SIMD_DISABLE_WARNINGS
2486 uint16x8_t
const data = vld1q_u16(
reinterpret_cast<uint16_t
const *
>(chars));
2490 uint16x8_t
const t0 = vsubq_u16(data, vmovq_n_u16(
'0'));
2491 uint16x8_t
const mask = vcltq_u16(t0, vmovq_n_u16(
'9' -
'0' + 1));
2493 if (vminvq_u16(mask) == 0xFFFF) {
2494 i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
2498 FASTFLOAT_SIMD_RESTORE_WARNINGS
2509#if defined(_MSC_VER) && _MSC_VER <= 1900
2510template <
typename UC>
2512template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
2515bool simd_parse_if_eight_digits_unrolled(UC
const *, uint64_t &) {
2519template <
typename UC, FASTFLOAT_ENABLE_IF(!tinyobj_ff::is_same<UC,
char>::value) = 0>
2520fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
2521loop_parse_if_eight_digits(UC
const *&p, UC
const *
const pend, uint64_t &i) {
2522 if (!has_simd_opt<UC>()) {
2525 while ((tinyobj_ff::distance(p, pend) >= 8) &&
2526 simd_parse_if_eight_digits_unrolled(
2532fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
2533loop_parse_if_eight_digits(
char const *&p,
char const *
const pend,
2536 while ((tinyobj_ff::distance(p, pend) >= 8) &&
2537 is_made_of_eight_digits_fast(read8_to_u64(p))) {
2539 parse_eight_digits_unrolled(read8_to_u64(
2545enum class parse_error {
2548 missing_integer_after_sign,
2550 missing_integer_or_dot_after_sign,
2552 leading_zeros_in_integer_part,
2554 no_digits_in_integer_part,
2557 no_digits_in_fractional_part,
2559 no_digits_in_mantissa,
2561 missing_exponential_part,
2564template <
typename UC>
struct parsed_number_string_t {
2565 int64_t exponent{0};
2566 uint64_t mantissa{0};
2567 UC
const *lastmatch{
nullptr};
2568 bool negative{
false};
2570 bool too_many_digits{
false};
2572 span<UC const> integer{};
2573 span<UC const> fraction{};
2574 parse_error error{parse_error::no_error};
2577using byte_span = span<char const>;
2578using parsed_number_string = parsed_number_string_t<char>;
2580template <
typename UC>
2581fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
2582report_parse_error(UC
const *p, parse_error error) {
2583 parsed_number_string_t<UC> answer;
2584 answer.valid =
false;
2585 answer.lastmatch = p;
2586 answer.error = error;
2592template <
bool basic_json_fmt,
typename UC>
2593fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
2594parse_number_string(UC
const *p, UC
const *pend,
2595 parse_options_t<UC> options)
noexcept {
2596 chars_format
const fmt = detail::adjust_for_feature_macros(options.format);
2597 UC
const decimal_point = options.decimal_point;
2599 parsed_number_string_t<UC> answer;
2600 answer.valid =
false;
2601 answer.too_many_digits =
false;
2603 answer.negative = (*p == UC(
'-'));
2605 if ((*p == UC(
'-')) || (uint64_t(fmt & chars_format::allow_leading_plus) &&
2606 !basic_json_fmt && *p == UC(
'+'))) {
2609 return report_parse_error<UC>(
2610 p, parse_error::missing_integer_or_dot_after_sign);
2612 FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2613 if (!is_integer(*p)) {
2614 return report_parse_error<UC>(p,
2615 parse_error::missing_integer_after_sign);
2619 if (!is_integer(*p) &&
2622 return report_parse_error<UC>(
2623 p, parse_error::missing_integer_or_dot_after_sign);
2627 UC
const *
const start_digits = p;
2631 while ((p != pend) && is_integer(*p)) {
2639 UC
const *
const end_of_integer_part = p;
2640 int64_t digit_count = int64_t(end_of_integer_part - start_digits);
2641 answer.integer = span<UC const>(start_digits,
size_t(digit_count));
2642 FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2644 if (digit_count == 0) {
2645 return report_parse_error<UC>(p, parse_error::no_digits_in_integer_part);
2647 if ((start_digits[0] == UC(
'0') && digit_count > 1)) {
2648 return report_parse_error<UC>(start_digits,
2649 parse_error::leading_zeros_in_integer_part);
2653 int64_t exponent = 0;
2654 bool const has_decimal_point = (p != pend) && (*p == decimal_point);
2655 if (has_decimal_point) {
2657 UC
const *before = p;
2660 loop_parse_if_eight_digits(p, pend, i);
2662 while ((p != pend) && is_integer(*p)) {
2663 uint8_t digit = uint8_t(*p - UC(
'0'));
2667 exponent = before - p;
2668 answer.fraction = span<UC const>(before,
size_t(p - before));
2669 digit_count -= exponent;
2671 FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2673 if (has_decimal_point && exponent == 0) {
2674 return report_parse_error<UC>(p,
2675 parse_error::no_digits_in_fractional_part);
2678 else if (digit_count == 0) {
2679 return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
2681 int64_t exp_number = 0;
2682 if ((uint64_t(fmt & chars_format::scientific) && (p != pend) &&
2683 ((UC(
'e') == *p) || (UC(
'E') == *p))) ||
2684 (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) &&
2685 ((UC(
'+') == *p) || (UC(
'-') == *p) || (UC(
'd') == *p) ||
2686 (UC(
'D') == *p)))) {
2687 UC
const *location_of_e = p;
2688 if ((UC(
'e') == *p) || (UC(
'E') == *p) || (UC(
'd') == *p) ||
2692 bool neg_exp =
false;
2693 if ((p != pend) && (UC(
'-') == *p)) {
2696 }
else if ((p != pend) &&
2701 if ((p == pend) || !is_integer(*p)) {
2702 if (!uint64_t(fmt & chars_format::fixed)) {
2706 return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2711 while ((p != pend) && is_integer(*p)) {
2712 uint8_t digit = uint8_t(*p - UC(
'0'));
2713 if (exp_number < 0x10000000) {
2714 exp_number = 10 * exp_number + digit;
2719 exp_number = -exp_number;
2721 exponent += exp_number;
2725 if (uint64_t(fmt & chars_format::scientific) &&
2726 !uint64_t(fmt & chars_format::fixed)) {
2727 return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2730 answer.lastmatch = p;
2731 answer.valid =
true;
2738 if (digit_count > 19) {
2743 UC
const *start = start_digits;
2744 while ((start != pend) && (*start == UC(
'0') || *start == decimal_point)) {
2745 if (*start == UC(
'0')) {
2751 if (digit_count > 19) {
2752 answer.too_many_digits =
true;
2757 p = answer.integer.ptr;
2758 UC
const *int_end = p + answer.integer.len();
2759 uint64_t
const minimal_nineteen_digit_integer{1000000000000000000};
2760 while ((i < minimal_nineteen_digit_integer) && (p != int_end)) {
2761 i = i * 10 + uint64_t(*p - UC(
'0'));
2764 if (i >= minimal_nineteen_digit_integer) {
2765 exponent = end_of_integer_part - p + exp_number;
2767 p = answer.fraction.ptr;
2768 UC
const *frac_end = p + answer.fraction.len();
2769 while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
2770 i = i * 10 + uint64_t(*p - UC(
'0'));
2773 exponent = answer.fraction.ptr - p + exp_number;
2778 answer.exponent = exponent;
2779 answer.mantissa = i;
2783template <
typename T,
typename UC>
2784fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2785parse_int_string(UC
const *p, UC
const *pend, T &value,
2786 parse_options_t<UC> options) {
2787 chars_format
const fmt = detail::adjust_for_feature_macros(options.format);
2788 int const base = options.base;
2790 from_chars_result_t<UC> answer;
2792 UC
const *
const first = p;
2794 bool const negative = (*p == UC(
'-'));
2795#ifdef FASTFLOAT_VISUAL_STUDIO
2796#pragma warning(push)
2797#pragma warning(disable : 4127)
2799 if (!tinyobj_ff::is_signed<T>::value && negative) {
2800#ifdef FASTFLOAT_VISUAL_STUDIO
2803 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
2807 if ((*p == UC(
'-')) ||
2808 (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC(
'+')))) {
2812 UC
const *
const start_num = p;
2814 while (p != pend && *p == UC(
'0')) {
2818 bool const has_leading_zeros = p > start_num;
2820 UC
const *
const start_digits = p;
2824 loop_parse_if_eight_digits(p, pend, i);
2827 uint8_t digit = ch_to_digit(*p);
2828 if (digit >= base) {
2831 i = uint64_t(base) * i + digit;
2835 size_t digit_count = size_t(p - start_digits);
2837 if (digit_count == 0) {
2838 if (has_leading_zeros) {
2840 answer.ec = tinyobj_ff::ff_errc();
2843 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
2852 size_t max_digits = max_digits_u64(base);
2853 if (digit_count > max_digits) {
2854 answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
2859 if (digit_count == max_digits && i < min_safe_u64(base)) {
2860 answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
2865 if (!tinyobj_ff::is_same<T, uint64_t>::value) {
2866 if (i > uint64_t(std::numeric_limits<T>::max()) + uint64_t(negative)) {
2867 answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
2873#ifdef FASTFLOAT_VISUAL_STUDIO
2874#pragma warning(push)
2875#pragma warning(disable : 4146)
2883 value = T(-std::numeric_limits<T>::max() -
2884 T(i - uint64_t(std::numeric_limits<T>::max())));
2885#ifdef FASTFLOAT_VISUAL_STUDIO
2892 answer.ec = tinyobj_ff::ff_errc();
2900#ifndef FASTFLOAT_FAST_TABLE_H
2901#define FASTFLOAT_FAST_TABLE_H
2903namespace fast_float {
2929template <
class unused =
void>
struct powers_template {
2931 constexpr static int smallest_power_of_five =
2932 binary_format<double>::smallest_power_of_ten();
2933 constexpr static int largest_power_of_five =
2934 binary_format<double>::largest_power_of_ten();
2935 constexpr static int number_of_entries =
2936 2 * (largest_power_of_five - smallest_power_of_five + 1);
2938 constexpr static uint64_t power_of_five_128[number_of_entries] = {
2939 0xeef453d6923bd65a, 0x113faa2906a13b3f,
2940 0x9558b4661b6565f8, 0x4ac7ca59a424c507,
2941 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649,
2942 0xe95a99df8ace6f53, 0xf4d82c2c107973dc,
2943 0x91d8a02bb6c10594, 0x79071b9b8a4be869,
2944 0xb64ec836a47146f9, 0x9748e2826cdee284,
2945 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25,
2946 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7,
2947 0xb208ef855c969f4f, 0xbdbd2d335e51a935,
2948 0xde8b2b66b3bc4723, 0xad2c788035e61382,
2949 0x8b16fb203055ac76, 0x4c3bcb5021afcc31,
2950 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d,
2951 0xd953e8624b85dd78, 0xd71d6dad34a2af0d,
2952 0x87d4713d6f33aa6b, 0x8672648c40e5ad68,
2953 0xa9c98d8ccb009506, 0x680efdaf511f18c2,
2954 0xd43bf0effdc0ba48, 0x212bd1b2566def2,
2955 0x84a57695fe98746d, 0x14bb630f7604b57,
2956 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d,
2957 0xcf42894a5dce35ea, 0x52064cac828675b9,
2958 0x818995ce7aa0e1b2, 0x7343efebd1940993,
2959 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8,
2960 0xca66fa129f9b60a6, 0xd41a26e077774ef6,
2961 0xfd00b897478238d0, 0x8920b098955522b4,
2962 0x9e20735e8cb16382, 0x55b46e5f5d5535b0,
2963 0xc5a890362fddbc62, 0xeb2189f734aa831d,
2964 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4,
2965 0x9a6bb0aa55653b2d, 0x47b233c92125366e,
2966 0xc1069cd4eabe89f8, 0x999ec0bb696e840a,
2967 0xf148440a256e2c76, 0xc00670ea43ca250d,
2968 0x96cd2a865764dbca, 0x380406926a5e5728,
2969 0xbc807527ed3e12bc, 0xc605083704f5ecf2,
2970 0xeba09271e88d976b, 0xf7864a44c633682e,
2971 0x93445b8731587ea3, 0x7ab3ee6afbe0211d,
2972 0xb8157268fdae9e4c, 0x5960ea05bad82964,
2973 0xe61acf033d1a45df, 0x6fb92487298e33bd,
2974 0x8fd0c16206306bab, 0xa5d3b6d479f8e056,
2975 0xb3c4f1ba87bc8696, 0x8f48a4899877186c,
2976 0xe0b62e2929aba83c, 0x331acdabfe94de87,
2977 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14,
2978 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9,
2979 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150,
2980 0x892731ac9faf056e, 0xbe311c083a225cd2,
2981 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406,
2982 0xd64d3d9db981787d, 0x92cbbccdad5b108,
2983 0x85f0468293f0eb4e, 0x25bbf56008c58ea5,
2984 0xa76c582338ed2621, 0xaf2af2b80af6f24e,
2985 0xd1476e2c07286faa, 0x1af5af660db4aee1,
2986 0x82cca4db847945ca, 0x50d98d9fc890ed4d,
2987 0xa37fce126597973c, 0xe50ff107bab528a0,
2988 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8,
2989 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a,
2990 0x9faacf3df73609b1, 0x77b191618c54e9ac,
2991 0xc795830d75038c1d, 0xd59df5b9ef6a2417,
2992 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d,
2993 0x9becce62836ac577, 0x4ee367f9430aec32,
2994 0xc2e801fb244576d5, 0x229c41f793cda73f,
2995 0xf3a20279ed56d48a, 0x6b43527578c1110f,
2996 0x9845418c345644d6, 0x830a13896b78aaa9,
2997 0xbe5691ef416bd60c, 0x23cc986bc656d553,
2998 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8,
2999 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9,
3000 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53,
3001 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68,
3002 0x91376c36d99995be, 0x23100809b9c21fa1,
3003 0xb58547448ffffb2d, 0xabd40a0c2832a78a,
3004 0xe2e69915b3fff9f9, 0x16c90c8f323f516c,
3005 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3,
3006 0xb1442798f49ffb4a, 0x99cd11cfdf41779c,
3007 0xdd95317f31c7fa1d, 0x40405643d711d583,
3008 0x8a7d3eef7f1cfc52, 0x482835ea666b2572,
3009 0xad1c8eab5ee43b66, 0xda3243650005eecf,
3010 0xd863b256369d4a40, 0x90bed43e40076a82,
3011 0x873e4f75e2224e68, 0x5a7744a6e804a291,
3012 0xa90de3535aaae202, 0x711515d0a205cb36,
3013 0xd3515c2831559a83, 0xd5a5b44ca873e03,
3014 0x8412d9991ed58091, 0xe858790afe9486c2,
3015 0xa5178fff668ae0b6, 0x626e974dbe39a872,
3016 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f,
3017 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99,
3018 0xa139029f6a239f72, 0x1c1fffc1ebc44e80,
3019 0xc987434744ac874e, 0xa327ffb266b56220,
3020 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8,
3021 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9,
3022 0xc4ce17b399107c22, 0xcb550fb4384d21d3,
3023 0xf6019da07f549b2b, 0x7e2a53a146606a48,
3024 0x99c102844f94e0fb, 0x2eda7444cbfc426d,
3025 0xc0314325637a1939, 0xfa911155fefb5308,
3026 0xf03d93eebc589f88, 0x793555ab7eba27ca,
3027 0x96267c7535b763b5, 0x4bc1558b2f3458de,
3028 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16,
3029 0xea9c227723ee8bcb, 0x465e15a979c1cadc,
3030 0x92a1958a7675175f, 0xbfacd89ec191ec9,
3031 0xb749faed14125d36, 0xcef980ec671f667b,
3032 0xe51c79a85916f484, 0x82b7e12780e7401a,
3033 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810,
3034 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15,
3035 0xdfbdcece67006ac9, 0x67a791e093e1d49a,
3036 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0,
3037 0xaecc49914078536d, 0x58fae9f773886e18,
3038 0xda7f5bf590966848, 0xaf39a475506a899e,
3039 0x888f99797a5e012d, 0x6d8406c952429603,
3040 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83,
3041 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64,
3042 0x855c3be0a17fcd26, 0x5cf2eea09a55067f,
3043 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e,
3044 0xd0601d8efc57b08b, 0xf13b94daf124da26,
3045 0x823c12795db6ce57, 0x76c53d08d6b70858,
3046 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e,
3047 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09,
3048 0xfe5d54150b090b02, 0xd3f93b35435d7c4c,
3049 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf,
3050 0xc6b8e9b0709f109a, 0x359ab6419ca1091b,
3051 0xf867241c8cc6d4c0, 0xc30163d203c94b62,
3052 0x9b407691d7fc44f8, 0x79e0de63425dcf1d,
3053 0xc21094364dfb5636, 0x985915fc12f542e4,
3054 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d,
3055 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42,
3056 0xbd8430bd08277231, 0x50c6ff782a838353,
3057 0xece53cec4a314ebd, 0xa4f8bf5635246428,
3058 0x940f4613ae5ed136, 0x871b7795e136be99,
3059 0xb913179899f68584, 0x28e2557b59846e3f,
3060 0xe757dd7ec07426e5, 0x331aeada2fe589cf,
3061 0x9096ea6f3848984f, 0x3ff0d2c85def7621,
3062 0xb4bca50b065abe63, 0xfed077a756b53a9,
3063 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894,
3064 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c,
3065 0xb080392cc4349dec, 0xbd8d794d96aacfb3,
3066 0xdca04777f541c567, 0xecf0d7a0fc5583a0,
3067 0x89e42caaf9491b60, 0xf41686c49db57244,
3068 0xac5d37d5b79b6239, 0x311c2875c522ced5,
3069 0xd77485cb25823ac7, 0x7d633293366b828b,
3070 0x86a8d39ef77164bc, 0xae5dff9c02033197,
3071 0xa8530886b54dbdeb, 0xd9f57f830283fdfc,
3072 0xd267caa862a12d66, 0xd072df63c324fd7b,
3073 0x8380dea93da4bc60, 0x4247cb9e59f71e6d,
3074 0xa46116538d0deb78, 0x52d9be85f074e608,
3075 0xcd795be870516656, 0x67902e276c921f8b,
3076 0x806bd9714632dff6, 0xba1cd8a3db53b6,
3077 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4,
3078 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd,
3079 0xfad2a4b13d1b5d6c, 0x796b805720085f81,
3080 0x9cc3a6eec6311a63, 0xcbe3303674053bb0,
3081 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c,
3082 0xf4f1b4d515acb93b, 0xee92fb5515482d44,
3083 0x991711052d8bf3c5, 0x751bdd152d4d1c4a,
3084 0xbf5cd54678eef0b6, 0xd262d45a78a0635d,
3085 0xef340a98172aace4, 0x86fb897116c87c34,
3086 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0,
3087 0xbae0a846d2195712, 0x8974836059cca109,
3088 0xe998d258869facd7, 0x2bd1a438703fc94b,
3089 0x91ff83775423cc06, 0x7b6306a34627ddcf,
3090 0xb67f6455292cbf08, 0x1a3bc84c17b1d542,
3091 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93,
3092 0x8e938662882af53e, 0x547eb47b7282ee9c,
3093 0xb23867fb2a35b28d, 0xe99e619a4f23aa43,
3094 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4,
3095 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04,
3096 0xae0b158b4738705e, 0x9624ab50b148d445,
3097 0xd98ddaee19068c76, 0x3badd624dd9b0957,
3098 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6,
3099 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c,
3100 0xd47487cc8470652b, 0x7647c3200069671f,
3101 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073,
3102 0xa5fb0a17c777cf09, 0xf468107100525890,
3103 0xcf79cc9db955c2cc, 0x7182148d4066eeb4,
3104 0x81ac1fe293d599bf, 0xc6f14cd848405530,
3105 0xa21727db38cb002f, 0xb8ada00e5a506a7c,
3106 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c,
3107 0xfd442e4688bd304a, 0x908f4a166d1da663,
3108 0x9e4a9cec15763e2e, 0x9a598e4e043287fe,
3109 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd,
3110 0xf7549530e188c128, 0xd12bee59e68ef47c,
3111 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce,
3112 0xc13a148e3032d6e7, 0xe36a52363c1faf01,
3113 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1,
3114 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9,
3115 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7,
3116 0xebdf661791d60f56, 0x111b495b3464ad21,
3117 0x936b9fcebb25c995, 0xcab10dd900beec34,
3118 0xb84687c269ef3bfb, 0x3d5d514f40eea742,
3119 0xe65829b3046b0afa, 0xcb4a5a3112a5112,
3120 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab,
3121 0xb3f4e093db73a093, 0x59ed216765690f56,
3122 0xe0f218b8d25088b8, 0x306869c13ec3532c,
3123 0x8c974f7383725573, 0x1e414218c73a13fb,
3124 0xafbd2350644eeacf, 0xe5d1929ef90898fa,
3125 0xdbac6c247d62a583, 0xdf45f746b74abf39,
3126 0x894bc396ce5da772, 0x6b8bba8c328eb783,
3127 0xab9eb47c81f5114f, 0x66ea92f3f326564,
3128 0xd686619ba27255a2, 0xc80a537b0efefebd,
3129 0x8613fd0145877585, 0xbd06742ce95f5f36,
3130 0xa798fc4196e952e7, 0x2c48113823b73704,
3131 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5,
3132 0x82ef85133de648c4, 0x9a984d73dbe722fb,
3133 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba,
3134 0xcc963fee10b7d1b3, 0x318df905079926a8,
3135 0xffbbcfe994e5c61f, 0xfdf17746497f7052,
3136 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633,
3137 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0,
3138 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0,
3139 0x9c1661a651213e2d, 0x6bea10ca65c084e,
3140 0xc31bfa0fe5698db8, 0x486e494fcff30a62,
3141 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa,
3142 0x986ddb5c6b3a76b7, 0xf89629465a75e01c,
3143 0xbe89523386091465, 0xf6bbb397f1135823,
3144 0xee2ba6c0678b597f, 0x746aa07ded582e2c,
3145 0x94db483840b717ef, 0xa8c2a44eb4571cdc,
3146 0xba121a4650e4ddeb, 0x92f34d62616ce413,
3147 0xe896a0d7e51e1566, 0x77b020baf9c81d17,
3148 0x915e2486ef32cd60, 0xace1474dc1d122e,
3149 0xb5b5ada8aaff80b8, 0xd819992132456ba,
3150 0xe3231912d5bf60e6, 0x10e1fff697ed6c69,
3151 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1,
3152 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2,
3153 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde,
3154 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b,
3155 0xad4ab7112eb3929d, 0x86c16c98d2c953c6,
3156 0xd89d64d57a607744, 0xe871c7bf077ba8b7,
3157 0x87625f056c7c4a8b, 0x11471cd764ad4972,
3158 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf,
3159 0xd389b47879823479, 0x4aff1d108d4ec2c3,
3160 0x843610cb4bf160cb, 0xcedf722a585139ba,
3161 0xa54394fe1eedb8fe, 0xc2974eb4ee658828,
3162 0xce947a3da6a9273e, 0x733d226229feea32,
3163 0x811ccc668829b887, 0x806357d5a3f525f,
3164 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7,
3165 0xc9bcff6034c13052, 0xfc89b393dd02f0b5,
3166 0xfc2c3f3841f17c67, 0xbbac2078d443ace2,
3167 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d,
3168 0xc5029163f384a931, 0xa9e795e65d4df11,
3169 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5,
3170 0x99ea0196163fa42e, 0x504bced1bf8e4e45,
3171 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6,
3172 0xf07da27a82c37088, 0x5d767327bb4e5a4c,
3173 0x964e858c91ba2655, 0x3a6a07f8d510f86f,
3174 0xbbe226efb628afea, 0x890489f70a55368b,
3175 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e,
3176 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d,
3177 0xb77ada0617e3bbcb, 0x9ce6ebb40173744,
3178 0xe55990879ddcaabd, 0xcc420a6a101d0515,
3179 0x8f57fa54c2a9eab6, 0x9fa946824a12232d,
3180 0xb32df8e9f3546564, 0x47939822dc96abf9,
3181 0xdff9772470297ebd, 0x59787e2b93bc56f7,
3182 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a,
3183 0xaefae51477a06b03, 0xede622920b6b23f1,
3184 0xdab99e59958885c4, 0xe95fab368e45eced,
3185 0x88b402f7fd75539b, 0x11dbcb0218ebb414,
3186 0xaae103b5fcd2a881, 0xd652bdc29f26a119,
3187 0xd59944a37c0752a2, 0x4be76d3346f0495f,
3188 0x857fcae62d8493a5, 0x6f70a4400c562ddb,
3189 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952,
3190 0xd097ad07a71f26b2, 0x7e2000a41346a7a7,
3191 0x825ecc24c873782f, 0x8ed400668c0c28c8,
3192 0xa2f67f2dfa90563b, 0x728900802f0f32fa,
3193 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9,
3194 0xfea126b7d78186bc, 0xe2f610c84987bfa8,
3195 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9,
3196 0xc6ede63fa05d3143, 0x91503d1c79720dbb,
3197 0xf8a95fcf88747d94, 0x75a44c6397ce912a,
3198 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba,
3199 0xc24452da229b021b, 0xfbe85badce996168,
3200 0xf2d56790ab41c2a2, 0xfae27299423fb9c3,
3201 0x97c560ba6b0919a5, 0xdccd879fc967d41a,
3202 0xbdb6b8e905cb600f, 0x5400e987bbc1c920,
3203 0xed246723473e3813, 0x290123e9aab23b68,
3204 0x9436c0760c86e30b, 0xf9a0b6720aaf6521,
3205 0xb94470938fa89bce, 0xf808e40e8d5b3e69,
3206 0xe7958cb87392c2c2, 0xb60b1d1230b20e04,
3207 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2,
3208 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3,
3209 0xe2280b6c20dd5232, 0x25c6da63c38de1b0,
3210 0x8d590723948a535f, 0x579c487e5a38ad0e,
3211 0xb0af48ec79ace837, 0x2d835a9df0c6d851,
3212 0xdcdb1b2798182244, 0xf8e431456cf88e65,
3213 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff,
3214 0xac8b2d36eed2dac5, 0xe272467e3d222f3f,
3215 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f,
3216 0x86ccbb52ea94baea, 0x98e947129fc2b4e9,
3217 0xa87fea27a539e9a5, 0x3f2398d747b36224,
3218 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad,
3219 0x83a3eeeef9153e89, 0x1953cf68300424ac,
3220 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7,
3221 0xcdb02555653131b6, 0x3792f412cb06794d,
3222 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0,
3223 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4,
3224 0xc8de047564d20a8b, 0xf245825a5a445275,
3225 0xfb158592be068d2e, 0xeed6e2f0f0d56712,
3226 0x9ced737bb6c4183d, 0x55464dd69685606b,
3227 0xc428d05aa4751e4c, 0xaa97e14c3c26b886,
3228 0xf53304714d9265df, 0xd53dd99f4b3066a8,
3229 0x993fe2c6d07b7fab, 0xe546a8038efe4029,
3230 0xbf8fdb78849a5f96, 0xde98520472bdd033,
3231 0xef73d256a5c0f77c, 0x963e66858f6d4440,
3232 0x95a8637627989aad, 0xdde7001379a44aa8,
3233 0xbb127c53b17ec159, 0x5560c018580d5d52,
3234 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6,
3235 0x9226712162ab070d, 0xcab3961304ca70e8,
3236 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22,
3237 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a,
3238 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242,
3239 0xb267ed1940f1c61c, 0x55f038b237591ed3,
3240 0xdf01e85f912e37a3, 0x6b6c46dec52f6688,
3241 0x8b61313bbabce2c6, 0x2323ac4b3b3da015,
3242 0xae397d8aa96c1b77, 0xabec975e0a0d081a,
3243 0xd9c7dced53c72255, 0x96e7bd358c904a21,
3244 0x881cea14545c7575, 0x7e50d64177da2e54,
3245 0xaa242499697392d2, 0xdde50bd1d5d0b9e9,
3246 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864,
3247 0x84ec3c97da624ab4, 0xbd5af13bef0b113e,
3248 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e,
3249 0xcfb11ead453994ba, 0x67de18eda5814af2,
3250 0x81ceb32c4b43fcf4, 0x80eacf948770ced7,
3251 0xa2425ff75e14fc31, 0xa1258379a94d028d,
3252 0xcad2f7f5359a3b3e, 0x96ee45813a04330,
3253 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc,
3254 0x9e74d1b791e07e48, 0x775ea264cf55347e,
3255 0xc612062576589dda, 0x95364afe032a819e,
3256 0xf79687aed3eec551, 0x3a83ddbd83f52205,
3257 0x9abe14cd44753b52, 0xc4926a9672793543,
3258 0xc16d9a0095928a27, 0x75b7053c0f178294,
3259 0xf1c90080baf72cb1, 0x5324c68b12dd6339,
3260 0x971da05074da7bee, 0xd3f6fc16ebca5e04,
3261 0xbce5086492111aea, 0x88f4bb1ca6bcf585,
3262 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6,
3263 0x9392ee8e921d5d07, 0x3aff322e62439fd0,
3264 0xb877aa3236a4b449, 0x9befeb9fad487c3,
3265 0xe69594bec44de15b, 0x4c2ebe687989a9b4,
3266 0x901d7cf73ab0acd9, 0xf9d37014bf60a11,
3267 0xb424dc35095cd80f, 0x538484c19ef38c95,
3268 0xe12e13424bb40e13, 0x2865a5f206b06fba,
3269 0x8cbccc096f5088cb, 0xf93f87b7442e45d4,
3270 0xafebff0bcb24aafe, 0xf78f69a51539d749,
3271 0xdbe6fecebdedd5be, 0xb573440e5a884d1c,
3272 0x89705f4136b4a597, 0x31680a88f8953031,
3273 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e,
3274 0xd6bf94d5e57a42bc, 0x3d32907604691b4d,
3275 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110,
3276 0xa7c5ac471b478423, 0xfcf80dc33721d54,
3277 0xd1b71758e219652b, 0xd3c36113404ea4a9,
3278 0x83126e978d4fdf3b, 0x645a1cac083126ea,
3279 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4,
3280 0xcccccccccccccccc, 0xcccccccccccccccd,
3281 0x8000000000000000, 0x0,
3282 0xa000000000000000, 0x0,
3283 0xc800000000000000, 0x0,
3284 0xfa00000000000000, 0x0,
3285 0x9c40000000000000, 0x0,
3286 0xc350000000000000, 0x0,
3287 0xf424000000000000, 0x0,
3288 0x9896800000000000, 0x0,
3289 0xbebc200000000000, 0x0,
3290 0xee6b280000000000, 0x0,
3291 0x9502f90000000000, 0x0,
3292 0xba43b74000000000, 0x0,
3293 0xe8d4a51000000000, 0x0,
3294 0x9184e72a00000000, 0x0,
3295 0xb5e620f480000000, 0x0,
3296 0xe35fa931a0000000, 0x0,
3297 0x8e1bc9bf04000000, 0x0,
3298 0xb1a2bc2ec5000000, 0x0,
3299 0xde0b6b3a76400000, 0x0,
3300 0x8ac7230489e80000, 0x0,
3301 0xad78ebc5ac620000, 0x0,
3302 0xd8d726b7177a8000, 0x0,
3303 0x878678326eac9000, 0x0,
3304 0xa968163f0a57b400, 0x0,
3305 0xd3c21bcecceda100, 0x0,
3306 0x84595161401484a0, 0x0,
3307 0xa56fa5b99019a5c8, 0x0,
3308 0xcecb8f27f4200f3a, 0x0,
3309 0x813f3978f8940984, 0x4000000000000000,
3310 0xa18f07d736b90be5, 0x5000000000000000,
3311 0xc9f2c9cd04674ede, 0xa400000000000000,
3312 0xfc6f7c4045812296, 0x4d00000000000000,
3313 0x9dc5ada82b70b59d, 0xf020000000000000,
3314 0xc5371912364ce305, 0x6c28000000000000,
3315 0xf684df56c3e01bc6, 0xc732000000000000,
3316 0x9a130b963a6c115c, 0x3c7f400000000000,
3317 0xc097ce7bc90715b3, 0x4b9f100000000000,
3318 0xf0bdc21abb48db20, 0x1e86d40000000000,
3319 0x96769950b50d88f4, 0x1314448000000000,
3320 0xbc143fa4e250eb31, 0x17d955a000000000,
3321 0xeb194f8e1ae525fd, 0x5dcfab0800000000,
3322 0x92efd1b8d0cf37be, 0x5aa1cae500000000,
3323 0xb7abc627050305ad, 0xf14a3d9e40000000,
3324 0xe596b7b0c643c719, 0x6d9ccd05d0000000,
3325 0x8f7e32ce7bea5c6f, 0xe4820023a2000000,
3326 0xb35dbf821ae4f38b, 0xdda2802c8a800000,
3327 0xe0352f62a19e306e, 0xd50b2037ad200000,
3328 0x8c213d9da502de45, 0x4526f422cc340000,
3329 0xaf298d050e4395d6, 0x9670b12b7f410000,
3330 0xdaf3f04651d47b4c, 0x3c0cdd765f114000,
3331 0x88d8762bf324cd0f, 0xa5880a69fb6ac800,
3332 0xab0e93b6efee0053, 0x8eea0d047a457a00,
3333 0xd5d238a4abe98068, 0x72a4904598d6d880,
3334 0x85a36366eb71f041, 0x47a6da2b7f864750,
3335 0xa70c3c40a64e6c51, 0x999090b65f67d924,
3336 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d,
3337 0x82818f1281ed449f, 0xbff8f10e7a8921a4,
3338 0xa321f2d7226895c7, 0xaff72d52192b6a0d,
3339 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490,
3340 0xfee50b7025c36a08, 0x2f236d04753d5b4,
3341 0x9f4f2726179a2245, 0x1d762422c946590,
3342 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5,
3343 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2,
3344 0x9b934c3b330c8577, 0x63cc55f49f88eb2f,
3345 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb,
3346 0xf316271c7fc3908a, 0x8bef464e3945ef7a,
3347 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac,
3348 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317,
3349 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd,
3350 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a,
3351 0xb975d6b6ee39e436, 0xb3e2fd538e122b44,
3352 0xe7d34c64a9c85d44, 0x60dbbca87196b616,
3353 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd,
3354 0xb51d13aea4a488dd, 0x6babab6398bdbe41,
3355 0xe264589a4dcdab14, 0xc696963c7eed2dd1,
3356 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2,
3357 0xb0de65388cc8ada8, 0x3b25a55f43294bcb,
3358 0xdd15fe86affad912, 0x49ef0eb713f39ebe,
3359 0x8a2dbf142dfcc7ab, 0x6e3569326c784337,
3360 0xacb92ed9397bf996, 0x49c2c37f07965404,
3361 0xd7e77a8f87daf7fb, 0xdc33745ec97be906,
3362 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3,
3363 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c,
3364 0xd2d80db02aabd62b, 0xf50a3fa490c30190,
3365 0x83c7088e1aab65db, 0x792667c6da79e0fa,
3366 0xa4b8cab1a1563f52, 0x577001b891185938,
3367 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86,
3368 0x80b05e5ac60b6178, 0x544f8158315b05b4,
3369 0xa0dc75f1778e39d6, 0x696361ae3db1c721,
3370 0xc913936dd571c84c, 0x3bc3a19cd1e38e9,
3371 0xfb5878494ace3a5f, 0x4ab48a04065c723,
3372 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76,
3373 0xc45d1df942711d9a, 0x3ba5d0bd324f8394,
3374 0xf5746577930d6500, 0xca8f44ec7ee36479,
3375 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb,
3376 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e,
3377 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e,
3378 0x95d04aee3b80ece5, 0xbba1f1d158724a12,
3379 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97,
3380 0xea1575143cf97226, 0xf52d09d71a3293bd,
3381 0x924d692ca61be758, 0x593c2626705f9c56,
3382 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c,
3383 0xe498f455c38b997a, 0xb6dfb9c0f956447,
3384 0x8edf98b59a373fec, 0x4724bd4189bd5eac,
3385 0xb2977ee300c50fe7, 0x58edec91ec2cb657,
3386 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed,
3387 0x8b865b215899f46c, 0xbd79e0d20082ee74,
3388 0xae67f1e9aec07187, 0xecd8590680a3aa11,
3389 0xda01ee641a708de9, 0xe80e6f4820cc9495,
3390 0x884134fe908658b2, 0x3109058d147fdcdd,
3391 0xaa51823e34a7eede, 0xbd4b46f0599fd415,
3392 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a,
3393 0x850fadc09923329e, 0x3e2cf6bc604ddb0,
3394 0xa6539930bf6bff45, 0x84db8346b786151c,
3395 0xcfe87f7cef46ff16, 0xe612641865679a63,
3396 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e,
3397 0xa26da3999aef7749, 0xe3be5e330f38f09d,
3398 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5,
3399 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6,
3400 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa,
3401 0xc646d63501a1511d, 0xb281e1fd541501b8,
3402 0xf7d88bc24209a565, 0x1f225a7ca91a4226,
3403 0x9ae757596946075f, 0x3375788de9b06958,
3404 0xc1a12d2fc3978937, 0x52d6b1641c83ae,
3405 0xf209787bb47d6b84, 0xc0678c5dbd23a49a,
3406 0x9745eb4d50ce6332, 0xf840b7ba963646e0,
3407 0xbd176620a501fbff, 0xb650e5a93bc3d898,
3408 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe,
3409 0x93ba47c980e98cdf, 0xc66f336c36b10137,
3410 0xb8a8d9bbe123f017, 0xb80b0047445d4184,
3411 0xe6d3102ad96cec1d, 0xa60dc059157491e5,
3412 0x9043ea1ac7e41392, 0x87c89837ad68db2f,
3413 0xb454e4a179dd1877, 0x29babe4598c311fb,
3414 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a,
3415 0x8ce2529e2734bb1d, 0x1899e4a65f58660c,
3416 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f,
3417 0xdc21a1171d42645d, 0x76707543f4fa1f73,
3418 0x899504ae72497eba, 0x6a06494a791c53a8,
3419 0xabfa45da0edbde69, 0x487db9d17636892,
3420 0xd6f8d7509292d603, 0x45a9d2845d3c42b6,
3421 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2,
3422 0xa7f26836f282b732, 0x8e6cac7768d7141e,
3423 0xd1ef0244af2364ff, 0x3207d795430cd926,
3424 0x8335616aed761f1f, 0x7f44e6bd49e807b8,
3425 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6,
3426 0xcd036837130890a1, 0x36dba887c37a8c0f,
3427 0x802221226be55a64, 0xc2494954da2c9789,
3428 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c,
3429 0xc83553c5c8965d3d, 0x6f92829494e5acc7,
3430 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9,
3431 0x9c69a97284b578d7, 0xff2a760414536efb,
3432 0xc38413cf25e2d70d, 0xfef5138519684aba,
3433 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69,
3434 0x98bf2f79d5993802, 0xef2f773ffbd97a61,
3435 0xbeeefb584aff8603, 0xaafb550ffacfd8fa,
3436 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38,
3437 0x952ab45cfa97a0b2, 0xdd945a747bf26183,
3438 0xba756174393d88df, 0x94f971119aeef9e4,
3439 0xe912b9d1478ceb17, 0x7a37cd5601aab85d,
3440 0x91abb422ccb812ee, 0xac62e055c10ab33a,
3441 0xb616a12b7fe617aa, 0x577b986b314d6009,
3442 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b,
3443 0x8e41ade9fbebc27d, 0x14588f13be847307,
3444 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8,
3445 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb,
3446 0x8aec23d680043bee, 0x25de7bb9480d5854,
3447 0xada72ccc20054ae9, 0xaf561aa79a10ae6a,
3448 0xd910f7ff28069da4, 0x1b2ba1518094da04,
3449 0x87aa9aff79042286, 0x90fb44d2f05d0842,
3450 0xa99541bf57452b28, 0x353a1607ac744a53,
3451 0xd3fa922f2d1675f2, 0x42889b8997915ce8,
3452 0x847c9b5d7c2e09b7, 0x69956135febada11,
3453 0xa59bc234db398c25, 0x43fab9837e699095,
3454 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb,
3455 0x8161afb94b44f57d, 0x1d1be0eebac278f5,
3456 0xa1ba1ba79e1632dc, 0x6462d92a69731732,
3457 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe,
3458 0xfcb2cb35e702af78, 0x5cda735244c3d43e,
3459 0x9defbf01b061adab, 0x3a0888136afa64a7,
3460 0xc56baec21c7a1916, 0x88aaa1845b8fdd0,
3461 0xf6c69a72a3989f5b, 0x8aad549e57273d45,
3462 0x9a3c2087a63f6399, 0x36ac54e2f678864b,
3463 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd,
3464 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5,
3465 0x969eb7c47859e743, 0x9f644ae5a4b1b325,
3466 0xbc4665b596706114, 0x873d5d9f0dde1fee,
3467 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea,
3468 0x9316ff75dd87cbd8, 0x9a7f12442d588f2,
3469 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f,
3470 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa,
3471 0x8fa475791a569d10, 0xf96e017d694487bc,
3472 0xb38d92d760ec4455, 0x37c981dcc395a9ac,
3473 0xe070f78d3927556a, 0x85bbe253f47b1417,
3474 0x8c469ab843b89562, 0x93956d7478ccec8e,
3475 0xaf58416654a6babb, 0x387ac8d1970027b2,
3476 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e,
3477 0x88fcf317f22241e2, 0x441fece3bdf81f03,
3478 0xab3c2fddeeaad25a, 0xd527e81cad7626c3,
3479 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074,
3480 0x85c7056562757456, 0xf6872d5667844e49,
3481 0xa738c6bebb12d16c, 0xb428f8ac016561db,
3482 0xd106f86e69d785c7, 0xe13336d701beba52,
3483 0x82a45b450226b39c, 0xecc0024661173473,
3484 0xa34d721642b06084, 0x27f002d7f95d0190,
3485 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4,
3486 0xff290242c83396ce, 0x7e67047175a15271,
3487 0x9f79a169bd203e41, 0xf0062c6e984d386,
3488 0xc75809c42c684dd1, 0x52c07b78a3e60868,
3489 0xf92e0c3537826145, 0xa7709a56ccdf8a82,
3490 0x9bbcc7a142b17ccb, 0x88a66076400bb691,
3491 0xc2abf989935ddbfe, 0x6acff893d00ea435,
3492 0xf356f7ebf83552fe, 0x583f6b8c4124d43,
3493 0x98165af37b2153de, 0xc3727a337a8b704a,
3494 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c,
3495 0xeda2ee1c7064130c, 0x1162def06f79df73,
3496 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8,
3497 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692,
3498 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437,
3499 0x910ab1d4db9914a0, 0x1d9c9892400a22a2,
3500 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b,
3501 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d,
3502 0x8da471a9de737e24, 0x5ceaecfed289e5d2,
3503 0xb10d8e1456105dad, 0x7425a83e872c5f47,
3504 0xdd50f1996b947518, 0xd12f124e28f77719,
3505 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f,
3506 0xace73cbfdc0bfb7b, 0x636cc64d1001550b,
3507 0xd8210befd30efa5a, 0x3c47f7e05401aa4e,
3508 0x8714a775e3e95c78, 0x65acfaec34810a71,
3509 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d,
3510 0xd31045a8341ca07c, 0x1ede48111209a050,
3511 0x83ea2b892091e44d, 0x934aed0aab460432,
3512 0xa4e4b66b68b65d60, 0xf81da84d5617853f,
3513 0xce1de40642e3f4b9, 0x36251260ab9d668e,
3514 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019,
3515 0xa1075a24e4421730, 0xb24cf65b8612f81f,
3516 0xc94930ae1d529cfc, 0xdee033f26797b627,
3517 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1,
3518 0x9d412e0806e88aa5, 0x8e1f289560ee864e,
3519 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2,
3520 0xf5b5d7ec8acb58a2, 0xae10af696774b1db,
3521 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29,
3522 0xbff610b0cc6edd3f, 0x17fd090a58d32af3,
3523 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0,
3524 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e,
3525 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1,
3526 0xea53df5fd18d5513, 0x84c86189216dc5ed,
3527 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4,
3528 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1,
3529 0xe4d5e82392a40515, 0xfabaf3feaa5334a,
3530 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e,
3531 0xb2c71d5bca9023f8, 0x743e20e9ef511012,
3532 0xdf78e4b2bd342cf6, 0x914da9246b255416,
3533 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e,
3534 0xae9672aba3d0c320, 0xa184ac2473b529b1,
3535 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e,
3536 0x8865899617fb1871, 0x7e2fa67c7a658892,
3537 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7,
3538 0xd51ea6fa85785631, 0x552a74227f3ea565,
3539 0x8533285c936b35de, 0xd53a88958f87275f,
3540 0xa67ff273b8460356, 0x8a892abaf368f137,
3541 0xd01fef10a657842c, 0x2d2b7569b0432d85,
3542 0x8213f56a67f6b29b, 0x9c3b29620e29fc73,
3543 0xa298f2c501f45f42, 0x8349f3ba91b47b8f,
3544 0xcb3f2f7642717713, 0x241c70a936219a73,
3545 0xfe0efb53d30dd4d7, 0xed238cd383aa0110,
3546 0x9ec95d1463e8a506, 0xf4363804324a40aa,
3547 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5,
3548 0xf81aa16fdc1b81da, 0xdd94b7868e94050a,
3549 0x9b10a4e5e9913128, 0xca7cf2b4191c8326,
3550 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0,
3551 0xf24a01a73cf2dccf, 0xbc633b39673c8cec,
3552 0x976e41088617ca01, 0xd5be0503e085d813,
3553 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18,
3554 0xec9c459d51852ba2, 0xddf8e7d60ed1219e,
3555 0x93e1ab8252f33b45, 0xcabb90e5c942b503,
3556 0xb8da1662e7b00a17, 0x3d6a751f3b936243,
3557 0xe7109bfba19c0c9d, 0xcc512670a783ad4,
3558 0x906a617d450187e2, 0x27fb2b80668b24c5,
3559 0xb484f9dc9641e9da, 0xb1f9f660802dedf6,
3560 0xe1a63853bbd26451, 0x5e7873f8a0396973,
3561 0x8d07e33455637eb2, 0xdb0b487b6423e1e8,
3562 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62,
3563 0xdc5c5301c56b75f7, 0x7641a140cc7810fb,
3564 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d,
3565 0xac2820d9623bf429, 0x546345fa9fbdcd44,
3566 0xd732290fbacaf133, 0xa97c177947ad4095,
3567 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d,
3568 0xa81f301449ee8c70, 0x5c68f256bfff5a74,
3569 0xd226fc195c6a2f8c, 0x73832eec6fff3111,
3570 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab,
3571 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55,
3572 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb,
3573 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3,
3574 0xa0555e361951c366, 0xd7e105bcc332621f,
3575 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7,
3576 0xfa856334878fc150, 0xb14f98f6f0feb951,
3577 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3,
3578 0xc3b8358109e84f07, 0xa862f80ec4700c8,
3579 0xf4a642e14c6262c8, 0xcd27bb612758c0fa,
3580 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c,
3581 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3,
3582 0xeeea5d5004981478, 0x1858ccfce06cac74,
3583 0x95527a5202df0ccb, 0xf37801e0c43ebc8,
3584 0xbaa718e68396cffd, 0xd30560258f54e6ba,
3585 0xe950df20247c83fd, 0x47c6b82ef32a2069,
3586 0x91d28b7416cdd27e, 0x4cdc331d57fa5441,
3587 0xb6472e511c81471d, 0xe0133fe4adf8e952,
3588 0xe3d8f9e563a198e5, 0x58180fddd97723a6,
3589 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648,
3593#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
3595template <
class unused>
3597 powers_template<unused>::power_of_five_128[number_of_entries];
3601using powers = powers_template<>;
3607#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H
3608#define FASTFLOAT_DECIMAL_TO_BINARY_H
3614namespace fast_float {
3621template <
int bit_precision>
3622fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
3623compute_product_approximation(int64_t q, uint64_t w) {
3624 int const index = 2 * int(q - powers::smallest_power_of_five);
3628 value128 firstproduct =
3629 full_multiplication(w, powers::power_of_five_128[index]);
3630 static_assert((bit_precision >= 0) && (bit_precision <= 64),
3631 " precision should be in (0,64]");
3632 constexpr uint64_t precision_mask =
3633 (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
3634 : uint64_t(0xFFFFFFFFFFFFFFFF);
3635 if ((firstproduct.high & precision_mask) ==
3640 value128 secondproduct =
3641 full_multiplication(w, powers::power_of_five_128[index + 1]);
3642 firstproduct.low += secondproduct.high;
3643 if (secondproduct.high > firstproduct.low) {
3644 firstproduct.high++;
3647 return firstproduct;
3666constexpr fastfloat_really_inline int32_t power(int32_t q)
noexcept {
3667 return (((152170 + 65536) * q) >> 16) + 63;
3673template <
typename binary>
3674fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa
3675compute_error_scaled(int64_t q, uint64_t w,
int lz)
noexcept {
3676 int hilz = int(w >> 63) ^ 1;
3677 adjusted_mantissa answer;
3678 answer.mantissa = w << hilz;
3679 int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent();
3680 answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 +
3687template <
typename binary>
3688fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
3689compute_error(int64_t q, uint64_t w)
noexcept {
3690 int lz = leading_zeroes(w);
3693 compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
3694 return compute_error_scaled<binary>(q, product.high, lz);
3702template <
typename binary>
3703fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
3704compute_float(int64_t q, uint64_t w)
noexcept {
3705 adjusted_mantissa answer;
3706 if ((w == 0) || (q < binary::smallest_power_of_ten())) {
3708 answer.mantissa = 0;
3712 if (q > binary::largest_power_of_ten()) {
3714 answer.power2 = binary::infinite_power();
3715 answer.mantissa = 0;
3722 int lz = leading_zeroes(w);
3732 compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
3742 int upperbit = int(product.high >> 63);
3743 int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3;
3745 answer.mantissa = product.high >> shift;
3747 answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz -
3748 binary::minimum_exponent());
3749 if (answer.power2 <= 0) {
3751 if (-answer.power2 + 1 >=
3755 answer.mantissa = 0;
3760 answer.mantissa >>= -answer.power2 + 1;
3764 answer.mantissa += (answer.mantissa & 1);
3765 answer.mantissa >>= 1;
3774 (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits()))
3783 if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) &&
3784 (q <= binary::max_exponent_round_to_even()) &&
3785 ((answer.mantissa & 3) == 1)) {
3791 if ((answer.mantissa << shift) == product.high) {
3792 answer.mantissa &= ~uint64_t(1);
3796 answer.mantissa += (answer.mantissa & 1);
3797 answer.mantissa >>= 1;
3798 if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {
3799 answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());
3803 answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());
3804 if (answer.power2 >= binary::infinite_power()) {
3805 answer.power2 = binary::infinite_power();
3806 answer.mantissa = 0;
3815#ifndef FASTFLOAT_BIGINT_H
3816#define FASTFLOAT_BIGINT_H
3821namespace fast_float {
3829#if defined(FASTFLOAT_64BIT) && !defined(__sparc)
3830#define FASTFLOAT_64BIT_LIMB 1
3831typedef uint64_t limb;
3832constexpr size_t limb_bits = 64;
3834#define FASTFLOAT_32BIT_LIMB
3835typedef uint32_t limb;
3836constexpr size_t limb_bits = 32;
3839typedef span<limb> limb_span;
3845constexpr size_t bigint_bits = 4000;
3846constexpr size_t bigint_limbs = bigint_bits / limb_bits;
3850template <u
int16_t size>
struct stackvec {
3855 stackvec() =
default;
3856 stackvec(stackvec
const &) =
delete;
3857 stackvec &operator=(stackvec
const &) =
delete;
3858 stackvec(stackvec &&) =
delete;
3859 stackvec &operator=(stackvec &&other) =
delete;
3862 FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
3863 FASTFLOAT_ASSERT(try_extend(s));
3866 FASTFLOAT_CONSTEXPR14 limb &operator[](
size_t index)
noexcept {
3867 FASTFLOAT_DEBUG_ASSERT(index < length);
3871 FASTFLOAT_CONSTEXPR14
const limb &operator[](
size_t index)
const noexcept {
3872 FASTFLOAT_DEBUG_ASSERT(index < length);
3877 FASTFLOAT_CONSTEXPR14
const limb &rindex(
size_t index)
const noexcept {
3878 FASTFLOAT_DEBUG_ASSERT(index < length);
3879 size_t rindex = length - index - 1;
3880 return data[rindex];
3884 FASTFLOAT_CONSTEXPR14
void set_len(
size_t len)
noexcept {
3885 length = uint16_t(len);
3888 constexpr size_t len() const noexcept {
return length; }
3890 constexpr bool is_empty() const noexcept {
return length == 0; }
3892 constexpr size_t capacity() const noexcept {
return size; }
3895 FASTFLOAT_CONSTEXPR14
void push_unchecked(limb value)
noexcept {
3896 data[length] = value;
3901 FASTFLOAT_CONSTEXPR14
bool try_push(limb value)
noexcept {
3902 if (len() < capacity()) {
3903 push_unchecked(value);
3911 FASTFLOAT_CONSTEXPR20
void extend_unchecked(limb_span s)
noexcept {
3912 limb *ptr = data + length;
3913 tinyobj_ff::copy_n(s.ptr, s.len(), ptr);
3914 set_len(len() + s.len());
3918 FASTFLOAT_CONSTEXPR20
bool try_extend(limb_span s)
noexcept {
3919 if (len() + s.len() <= capacity()) {
3920 extend_unchecked(s);
3930 FASTFLOAT_CONSTEXPR20
3931 void resize_unchecked(
size_t new_len, limb value)
noexcept {
3932 if (new_len > len()) {
3933 size_t count = new_len - len();
3934 limb *first = data + len();
3935 limb *last = first + count;
3936 tinyobj_ff::fill(first, last, value);
3944 FASTFLOAT_CONSTEXPR20
bool try_resize(
size_t new_len, limb value)
noexcept {
3945 if (new_len > capacity()) {
3948 resize_unchecked(new_len, value);
3956 FASTFLOAT_CONSTEXPR14
bool nonzero(
size_t index)
const noexcept {
3957 while (index < len()) {
3958 if (rindex(index) != 0) {
3967 FASTFLOAT_CONSTEXPR14
void normalize() noexcept {
3968 while (len() > 0 && rindex(0) == 0) {
3974fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
3975empty_hi64(
bool &truncated)
noexcept {
3980fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
3981uint64_hi64(uint64_t r0,
bool &truncated)
noexcept {
3983 int shl = leading_zeroes(r0);
3987fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
3988uint64_hi64(uint64_t r0, uint64_t r1,
bool &truncated)
noexcept {
3989 int shl = leading_zeroes(r0);
3991 truncated = r1 != 0;
3995 truncated = (r1 << shl) != 0;
3996 return (r0 << shl) | (r1 >> shr);
4000fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4001uint32_hi64(uint32_t r0,
bool &truncated)
noexcept {
4002 return uint64_hi64(r0, truncated);
4005fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4006uint32_hi64(uint32_t r0, uint32_t r1,
bool &truncated)
noexcept {
4009 return uint64_hi64((x0 << 32) | x1, truncated);
4012fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4013uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2,
bool &truncated)
noexcept {
4017 return uint64_hi64(x0, (x1 << 32) | x2, truncated);
4024fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
4025scalar_add(limb x, limb y,
bool &overflow)
noexcept {
4028#if defined(__has_builtin)
4029#if __has_builtin(__builtin_add_overflow)
4030 if (!cpp20_and_in_constexpr()) {
4031 overflow = __builtin_add_overflow(x, y, &z);
4044fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
4045scalar_mul(limb x, limb y, limb &carry)
noexcept {
4046#ifdef FASTFLOAT_64BIT_LIMB
4047#if defined(__SIZEOF_INT128__)
4049 __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
4050 carry = limb(z >> limb_bits);
4055 value128 z = full_multiplication(x, y);
4057 z.low = scalar_add(z.low, carry, overflow);
4058 z.high += uint64_t(overflow);
4063 uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
4064 carry = limb(z >> limb_bits);
4071template <u
int16_t size>
4072inline FASTFLOAT_CONSTEXPR20
bool small_add_from(stackvec<size> &vec, limb y,
4073 size_t start)
noexcept {
4074 size_t index = start;
4077 while (carry != 0 && index < vec.len()) {
4078 vec[index] = scalar_add(vec[index], carry, overflow);
4079 carry = limb(overflow);
4083 FASTFLOAT_TRY(vec.try_push(carry));
4089template <u
int16_t size>
4090fastfloat_really_inline FASTFLOAT_CONSTEXPR20
bool
4091small_add(stackvec<size> &vec, limb y)
noexcept {
4092 return small_add_from(vec, y, 0);
4096template <u
int16_t size>
4097inline FASTFLOAT_CONSTEXPR20
bool small_mul(stackvec<size> &vec,
4100 for (
size_t index = 0; index < vec.len(); index++) {
4101 vec[index] = scalar_mul(vec[index], y, carry);
4104 FASTFLOAT_TRY(vec.try_push(carry));
4111template <u
int16_t size>
4112FASTFLOAT_CONSTEXPR20
bool large_add_from(stackvec<size> &x, limb_span y,
4113 size_t start)
noexcept {
4116 if (x.len() < start || y.len() > x.len() - start) {
4117 FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
4121 for (
size_t index = 0; index < y.len(); index++) {
4122 limb xi = x[index + start];
4126 xi = scalar_add(xi, yi, c1);
4128 xi = scalar_add(xi, 1, c2);
4130 x[index + start] = xi;
4136 FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
4142template <u
int16_t size>
4143fastfloat_really_inline FASTFLOAT_CONSTEXPR20
bool
4144large_add_from(stackvec<size> &x, limb_span y)
noexcept {
4145 return large_add_from(x, y, 0);
4149template <u
int16_t size>
4150FASTFLOAT_CONSTEXPR20
bool long_mul(stackvec<size> &x, limb_span y)
noexcept {
4151 limb_span xs = limb_span(x.data, x.len());
4152 stackvec<size> z(xs);
4153 limb_span zs = limb_span(z.data, z.len());
4157 FASTFLOAT_TRY(small_mul(x, y0));
4158 for (
size_t index = 1; index < y.len(); index++) {
4164 FASTFLOAT_TRY(zi.try_extend(zs));
4165 FASTFLOAT_TRY(small_mul(zi, yi));
4166 limb_span zis = limb_span(zi.data, zi.len());
4167 FASTFLOAT_TRY(large_add_from(x, zis, index));
4177template <u
int16_t size>
4178FASTFLOAT_CONSTEXPR20
bool large_mul(stackvec<size> &x, limb_span y)
noexcept {
4180 FASTFLOAT_TRY(small_mul(x, y[0]));
4182 FASTFLOAT_TRY(long_mul(x, y));
4187template <
typename =
void>
struct pow5_tables {
4188 static constexpr uint32_t large_step = 135;
4189 static constexpr uint64_t small_power_of_5[] = {
4213 11920928955078125UL,
4214 59604644775390625UL,
4215 298023223876953125UL,
4216 1490116119384765625UL,
4217 7450580596923828125UL,
4219#ifdef FASTFLOAT_64BIT_LIMB
4220 constexpr static limb large_power_of_5[] = {
4221 1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
4222 10482974169319127550UL, 198276706040285095UL};
4224 constexpr static limb large_power_of_5[] = {
4225 4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
4226 1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
4230#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
4232template <
typename T>
constexpr uint32_t pow5_tables<T>::large_step;
4234template <
typename T>
constexpr uint64_t pow5_tables<T>::small_power_of_5[];
4236template <
typename T>
constexpr limb pow5_tables<T>::large_power_of_5[];
4244struct bigint : pow5_tables<> {
4246 stackvec<bigint_limbs> vec;
4248 FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
4250 bigint(bigint
const &) =
delete;
4251 bigint &operator=(bigint
const &) =
delete;
4252 bigint(bigint &&) =
delete;
4253 bigint &operator=(bigint &&other) =
delete;
4255 FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() {
4256#ifdef FASTFLOAT_64BIT_LIMB
4257 vec.push_unchecked(value);
4259 vec.push_unchecked(uint32_t(value));
4260 vec.push_unchecked(uint32_t(value >> 32));
4267 FASTFLOAT_CONSTEXPR20 uint64_t hi64(
bool &truncated)
const noexcept {
4268#ifdef FASTFLOAT_64BIT_LIMB
4269 if (vec.len() == 0) {
4270 return empty_hi64(truncated);
4271 }
else if (vec.len() == 1) {
4272 return uint64_hi64(vec.rindex(0), truncated);
4274 uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
4275 truncated |= vec.nonzero(2);
4279 if (vec.len() == 0) {
4280 return empty_hi64(truncated);
4281 }
else if (vec.len() == 1) {
4282 return uint32_hi64(vec.rindex(0), truncated);
4283 }
else if (vec.len() == 2) {
4284 return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
4287 uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
4288 truncated |= vec.nonzero(3);
4300 FASTFLOAT_CONSTEXPR20
int compare(bigint
const &other)
const noexcept {
4301 if (vec.len() > other.vec.len()) {
4303 }
else if (vec.len() < other.vec.len()) {
4306 for (
size_t index = vec.len(); index > 0; index--) {
4307 limb xi = vec[index - 1];
4308 limb yi = other.vec[index - 1];
4311 }
else if (xi < yi) {
4321 FASTFLOAT_CONSTEXPR20
bool shl_bits(
size_t n)
noexcept {
4327 FASTFLOAT_DEBUG_ASSERT(n != 0);
4328 FASTFLOAT_DEBUG_ASSERT(n <
sizeof(limb) * 8);
4331 size_t shr = limb_bits - shl;
4333 for (
size_t index = 0; index < vec.len(); index++) {
4334 limb xi = vec[index];
4335 vec[index] = (xi << shl) | (prev >> shr);
4339 limb carry = prev >> shr;
4341 return vec.try_push(carry);
4347 FASTFLOAT_CONSTEXPR20
bool shl_limbs(
size_t n)
noexcept {
4348 FASTFLOAT_DEBUG_ASSERT(n != 0);
4349 if (n + vec.len() > vec.capacity()) {
4351 }
else if (!vec.is_empty()) {
4353 limb *dst = vec.data + n;
4354 limb
const *src = vec.data;
4355 tinyobj_ff::copy_backward(src, src + vec.len(), dst + vec.len());
4357 limb *first = vec.data;
4358 limb *last = first + n;
4359 tinyobj_ff::fill(first, last, 0);
4360 vec.set_len(n + vec.len());
4368 FASTFLOAT_CONSTEXPR20
bool shl(
size_t n)
noexcept {
4369 size_t rem = n % limb_bits;
4370 size_t div = n / limb_bits;
4372 FASTFLOAT_TRY(shl_bits(rem));
4375 FASTFLOAT_TRY(shl_limbs(div));
4381 FASTFLOAT_CONSTEXPR20
int ctlz() const noexcept {
4382 if (vec.is_empty()) {
4385#ifdef FASTFLOAT_64BIT_LIMB
4386 return leading_zeroes(vec.rindex(0));
4389 uint64_t r0 = vec.rindex(0);
4390 return leading_zeroes(r0 << 32);
4396 FASTFLOAT_CONSTEXPR20
int bit_length() const noexcept {
4398 return int(limb_bits * vec.len()) - lz;
4401 FASTFLOAT_CONSTEXPR20
bool mul(limb y)
noexcept {
return small_mul(vec, y); }
4403 FASTFLOAT_CONSTEXPR20
bool add(limb y)
noexcept {
return small_add(vec, y); }
4406 FASTFLOAT_CONSTEXPR20
bool pow2(uint32_t exp)
noexcept {
return shl(exp); }
4409 FASTFLOAT_CONSTEXPR20
bool pow5(uint32_t exp)
noexcept {
4411 size_t large_length =
sizeof(large_power_of_5) /
sizeof(limb);
4412 limb_span large = limb_span(large_power_of_5, large_length);
4413 while (exp >= large_step) {
4414 FASTFLOAT_TRY(large_mul(vec, large));
4417#ifdef FASTFLOAT_64BIT_LIMB
4418 uint32_t small_step = 27;
4419 limb max_native = 7450580596923828125UL;
4421 uint32_t small_step = 13;
4422 limb max_native = 1220703125U;
4424 while (exp >= small_step) {
4425 FASTFLOAT_TRY(small_mul(vec, max_native));
4432 FASTFLOAT_TRY(small_mul(
4433 vec, limb(((
void)small_power_of_5[0], small_power_of_5[exp]))));
4440 FASTFLOAT_CONSTEXPR20
bool pow10(uint32_t exp)
noexcept {
4441 FASTFLOAT_TRY(pow5(exp));
4450#ifndef FASTFLOAT_DIGIT_COMPARISON_H
4451#define FASTFLOAT_DIGIT_COMPARISON_H
4456namespace fast_float {
4459constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
4475 10000000000000000UL,
4476 100000000000000000UL,
4477 1000000000000000000UL,
4478 10000000000000000000UL};
4484template <
typename UC>
4485fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
4486scientific_exponent(parsed_number_string_t<UC> &num)
noexcept {
4487 uint64_t mantissa = num.mantissa;
4488 int32_t exponent = int32_t(num.exponent);
4489 while (mantissa >= 10000) {
4493 while (mantissa >= 100) {
4497 while (mantissa >= 10) {
4505template <
typename T>
4506fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4507to_extended(T value)
noexcept {
4508 using equiv_uint = equiv_uint_t<T>;
4509 constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
4510 constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
4511 constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
4513 adjusted_mantissa am;
4514 int32_t bias = binary_format<T>::mantissa_explicit_bits() -
4515 binary_format<T>::minimum_exponent();
4517#if FASTFLOAT_HAS_BIT_CAST
4518 bits = std::bit_cast<equiv_uint>(value);
4520 ::memcpy(&bits, &value,
sizeof(T));
4522 if ((bits & exponent_mask) == 0) {
4524 am.power2 = 1 - bias;
4525 am.mantissa = bits & mantissa_mask;
4528 am.power2 = int32_t((bits & exponent_mask) >>
4529 binary_format<T>::mantissa_explicit_bits());
4531 am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
4540template <
typename T>
4541fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4542to_extended_halfway(T value)
noexcept {
4543 adjusted_mantissa am = to_extended(value);
4551template <
typename T,
typename callback>
4552fastfloat_really_inline FASTFLOAT_CONSTEXPR14
void round(adjusted_mantissa &am,
4553 callback cb)
noexcept {
4554 int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
4555 if (-am.power2 >= mantissa_shift) {
4557 int32_t shift = -am.power2 + 1;
4558 cb(am, tinyobj_ff::min_val<int32_t>(shift, 64));
4560 am.power2 = (am.mantissa <
4561 (uint64_t(1) << binary_format<T>::mantissa_explicit_bits()))
4568 cb(am, mantissa_shift);
4572 (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
4573 am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
4578 am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
4579 if (am.power2 >= binary_format<T>::infinite_power()) {
4580 am.power2 = binary_format<T>::infinite_power();
4585template <
typename callback>
4586fastfloat_really_inline FASTFLOAT_CONSTEXPR14
void
4587round_nearest_tie_even(adjusted_mantissa &am, int32_t shift,
4588 callback cb)
noexcept {
4589 uint64_t
const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1;
4590 uint64_t
const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1);
4591 uint64_t truncated_bits = am.mantissa & mask;
4592 bool is_above = truncated_bits > halfway;
4593 bool is_halfway = truncated_bits == halfway;
4599 am.mantissa >>= shift;
4603 bool is_odd = (am.mantissa & 1) == 1;
4604 am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
4607fastfloat_really_inline FASTFLOAT_CONSTEXPR14
void
4608round_down(adjusted_mantissa &am, int32_t shift)
noexcept {
4612 am.mantissa >>= shift;
4617template <
typename UC>
4618fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
4619skip_zeros(UC
const *&first, UC
const *last)
noexcept {
4621 while (!cpp20_and_in_constexpr() &&
4622 tinyobj_ff::distance(first, last) >= int_cmp_len<UC>()) {
4623 ::memcpy(&val, first,
sizeof(uint64_t));
4624 if (val != int_cmp_zeros<UC>()) {
4627 first += int_cmp_len<UC>();
4629 while (first != last) {
4630 if (*first != UC(
'0')) {
4639template <
typename UC>
4640fastfloat_really_inline FASTFLOAT_CONSTEXPR20
bool
4641is_truncated(UC
const *first, UC
const *last)
noexcept {
4644 while (!cpp20_and_in_constexpr() &&
4645 tinyobj_ff::distance(first, last) >= int_cmp_len<UC>()) {
4646 ::memcpy(&val, first,
sizeof(uint64_t));
4647 if (val != int_cmp_zeros<UC>()) {
4650 first += int_cmp_len<UC>();
4652 while (first != last) {
4653 if (*first != UC(
'0')) {
4661template <
typename UC>
4662fastfloat_really_inline FASTFLOAT_CONSTEXPR20
bool
4663is_truncated(span<UC const> s)
noexcept {
4664 return is_truncated(s.ptr, s.ptr + s.len());
4667template <
typename UC>
4668fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
4669parse_eight_digits(UC
const *&p, limb &value,
size_t &counter,
4670 size_t &count)
noexcept {
4671 value = value * 100000000 + parse_eight_digits_unrolled(p);
4677template <
typename UC>
4678fastfloat_really_inline FASTFLOAT_CONSTEXPR14
void
4679parse_one_digit(UC
const *&p, limb &value,
size_t &counter,
4680 size_t &count)
noexcept {
4681 value = value * 10 + limb(*p - UC(
'0'));
4687fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
4688add_native(bigint &big, limb power, limb value)
noexcept {
4693fastfloat_really_inline FASTFLOAT_CONSTEXPR20
void
4694round_up_bigint(bigint &big,
size_t &count)
noexcept {
4697 add_native(big, 10, 1);
4702template <
typename UC>
4703inline FASTFLOAT_CONSTEXPR20
void
4704parse_mantissa(bigint &result, parsed_number_string_t<UC> &num,
4705 size_t max_digits,
size_t &digits)
noexcept {
4712#ifdef FASTFLOAT_64BIT_LIMB
4719 UC
const *p = num.integer.ptr;
4720 UC
const *pend = p + num.integer.len();
4721 skip_zeros(p, pend);
4724 while ((tinyobj_ff::distance(p, pend) >= 8) && (step - counter >= 8) &&
4725 (max_digits - digits >= 8)) {
4726 parse_eight_digits(p, value, counter, digits);
4728 while (counter < step && p != pend && digits < max_digits) {
4729 parse_one_digit(p, value, counter, digits);
4731 if (digits == max_digits) {
4733 add_native(result, limb(powers_of_ten_uint64[counter]), value);
4734 bool truncated = is_truncated(p, pend);
4735 if (num.fraction.ptr !=
nullptr) {
4736 truncated |= is_truncated(num.fraction);
4739 round_up_bigint(result, digits);
4743 add_native(result, limb(powers_of_ten_uint64[counter]), value);
4750 if (num.fraction.ptr !=
nullptr) {
4751 p = num.fraction.ptr;
4752 pend = p + num.fraction.len();
4754 skip_zeros(p, pend);
4758 while ((tinyobj_ff::distance(p, pend) >= 8) && (step - counter >= 8) &&
4759 (max_digits - digits >= 8)) {
4760 parse_eight_digits(p, value, counter, digits);
4762 while (counter < step && p != pend && digits < max_digits) {
4763 parse_one_digit(p, value, counter, digits);
4765 if (digits == max_digits) {
4767 add_native(result, limb(powers_of_ten_uint64[counter]), value);
4768 bool truncated = is_truncated(p, pend);
4770 round_up_bigint(result, digits);
4774 add_native(result, limb(powers_of_ten_uint64[counter]), value);
4782 add_native(result, limb(powers_of_ten_uint64[counter]), value);
4786template <
typename T>
4787inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4788positive_digit_comp(bigint &bigmant, int32_t exponent)
noexcept {
4789 FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
4790 adjusted_mantissa answer;
4792 answer.mantissa = bigmant.hi64(truncated);
4793 int bias = binary_format<T>::mantissa_explicit_bits() -
4794 binary_format<T>::minimum_exponent();
4795 answer.power2 = bigmant.bit_length() - 64 + bias;
4797 round<T>(answer, [truncated](adjusted_mantissa &a, int32_t shift) {
4798 round_nearest_tie_even(
4800 [truncated](
bool is_odd,
bool is_halfway,
bool is_above) ->
bool {
4801 return is_above || (is_halfway && truncated) ||
4802 (is_odd && is_halfway);
4814template <
typename T>
4815inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
4816 bigint &bigmant, adjusted_mantissa am, int32_t exponent)
noexcept {
4817 bigint &real_digits = bigmant;
4818 int32_t real_exp = exponent;
4821 adjusted_mantissa am_b = am;
4825 [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); });
4827 to_float(
false, am_b, b);
4828 adjusted_mantissa theor = to_extended_halfway(b);
4829 bigint theor_digits(theor.mantissa);
4830 int32_t theor_exp = theor.power2;
4833 int32_t pow2_exp = theor_exp - real_exp;
4834 uint32_t pow5_exp = uint32_t(-real_exp);
4835 if (pow5_exp != 0) {
4836 FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));
4839 FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp)));
4840 }
else if (pow2_exp < 0) {
4841 FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
4845 int ord = real_digits.compare(theor_digits);
4846 adjusted_mantissa answer = am;
4847 round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
4848 round_nearest_tie_even(
4849 a, shift, [ord](
bool is_odd,
bool _,
bool __) ->
bool {
4854 }
else if (ord < 0) {
4878template <
typename T,
typename UC>
4879inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4880digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am)
noexcept {
4882 am.power2 -= invalid_am_bias;
4884 int32_t sci_exp = scientific_exponent(num);
4885 size_t max_digits = binary_format<T>::max_digits();
4888 parse_mantissa(bigmant, num, max_digits, digits);
4890 int32_t exponent = sci_exp + 1 - int32_t(digits);
4891 if (exponent >= 0) {
4892 return positive_digit_comp<T>(bigmant, exponent);
4894 return negative_digit_comp<T>(bigmant, am, exponent);
4902#ifndef FASTFLOAT_PARSE_NUMBER_H
4903#define FASTFLOAT_PARSE_NUMBER_H
4910namespace fast_float {
4918template <
typename T,
typename UC>
4919from_chars_result_t<UC>
4920 FASTFLOAT_CONSTEXPR14 parse_infnan(UC
const *first, UC
const *last,
4921 T &value, chars_format fmt)
noexcept {
4922 from_chars_result_t<UC> answer{};
4924 answer.ec = tinyobj_ff::ff_errc();
4926 bool const minusSign = (*first == UC(
'-'));
4928 if ((*first == UC(
'-')) ||
4929 (uint64_t(fmt & chars_format::allow_leading_plus) &&
4930 (*first == UC(
'+')))) {
4933 if (last - first >= 3) {
4934 if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
4935 answer.ptr = (first += 3);
4936 value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
4937 : std::numeric_limits<T>::quiet_NaN();
4940 if (first != last && *first == UC(
'(')) {
4941 for (UC
const *ptr = first + 1; ptr != last; ++ptr) {
4942 if (*ptr == UC(
')')) {
4943 answer.ptr = ptr + 1;
4945 }
else if (!((UC(
'a') <= *ptr && *ptr <= UC(
'z')) ||
4946 (UC(
'A') <= *ptr && *ptr <= UC(
'Z')) ||
4947 (UC(
'0') <= *ptr && *ptr <= UC(
'9')) || *ptr == UC(
'_')))
4953 if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
4954 if ((last - first >= 8) &&
4955 fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
4956 answer.ptr = first + 8;
4958 answer.ptr = first + 3;
4960 value = minusSign ? -std::numeric_limits<T>::infinity()
4961 : std::numeric_limits<T>::infinity();
4965 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
4974fastfloat_really_inline
bool rounds_to_nearest() noexcept {
4976#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
4995 static float volatile fmin = std::numeric_limits<float>::min();
5012#ifdef FASTFLOAT_VISUAL_STUDIO
5013#pragma warning(push)
5017#elif defined(__clang__)
5018#pragma clang diagnostic push
5019#pragma clang diagnostic ignored "-Wfloat-equal"
5020#elif defined(__GNUC__)
5021#pragma GCC diagnostic push
5022#pragma GCC diagnostic ignored "-Wfloat-equal"
5024 return (fmini + 1.0f == 1.0f - fmini);
5025#ifdef FASTFLOAT_VISUAL_STUDIO
5027#elif defined(__clang__)
5028#pragma clang diagnostic pop
5029#elif defined(__GNUC__)
5030#pragma GCC diagnostic pop
5036template <
typename T>
struct from_chars_caller {
5037 template <
typename UC>
5038 FASTFLOAT_CONSTEXPR20
static from_chars_result_t<UC>
5039 call(UC
const *first, UC
const *last, T &value,
5040 parse_options_t<UC> options)
noexcept {
5041 return from_chars_advanced(first, last, value, options);
5045#ifdef __STDCPP_FLOAT32_T__
5046template <>
struct from_chars_caller<std::float32_t> {
5047 template <
typename UC>
5048 FASTFLOAT_CONSTEXPR20
static from_chars_result_t<UC>
5049 call(UC
const *first, UC
const *last, std::float32_t &value,
5050 parse_options_t<UC> options)
noexcept {
5055 auto ret = from_chars_advanced(first, last, val, options);
5062#ifdef __STDCPP_FLOAT64_T__
5063template <>
struct from_chars_caller<std::float64_t> {
5064 template <
typename UC>
5065 FASTFLOAT_CONSTEXPR20
static from_chars_result_t<UC>
5066 call(UC
const *first, UC
const *last, std::float64_t &value,
5067 parse_options_t<UC> options)
noexcept {
5072 auto ret = from_chars_advanced(first, last, val, options);
5079template <
typename T,
typename UC,
typename>
5080FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5081from_chars(UC
const *first, UC
const *last, T &value,
5082 chars_format fmt )
noexcept {
5083 return from_chars_caller<T>::call(first, last, value,
5084 parse_options_t<UC>(fmt));
5092template <
typename T,
typename UC>
5093FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5094from_chars_advanced(parsed_number_string_t<UC> &pns, T &value)
noexcept {
5096 static_assert(is_supported_float_type<T>::value,
5097 "only some floating-point types are supported");
5098 static_assert(is_supported_char_type<UC>::value,
5099 "only char, wchar_t, char16_t and char32_t are supported");
5101 from_chars_result_t<UC> answer;
5103 answer.ec = tinyobj_ff::ff_errc();
5104 answer.ptr = pns.lastmatch;
5110 if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
5111 pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
5112 !pns.too_many_digits) {
5120 if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
5123 if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
5124 value = T(pns.mantissa);
5125 if (pns.exponent < 0) {
5126 value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
5128 value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
5139 if (pns.exponent >= 0 &&
5141 binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
5142#if defined(__clang__) || defined(FASTFLOAT_32BIT)
5144 if (pns.mantissa == 0) {
5145 value = pns.negative ? T(-0.) : T(0.);
5149 value = T(pns.mantissa) *
5150 binary_format<T>::exact_power_of_ten(pns.exponent);
5158 adjusted_mantissa am =
5159 compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
5160 if (pns.too_many_digits && am.power2 >= 0) {
5161 if (am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
5162 am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
5168 if (am.power2 < 0) {
5169 am = digit_comp<T>(pns, am);
5171 to_float(pns.negative, am, value);
5173 if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) ||
5174 am.power2 == binary_format<T>::infinite_power()) {
5175 answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
5180template <
typename T,
typename UC>
5181FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5182from_chars_float_advanced(UC
const *first, UC
const *last, T &value,
5183 parse_options_t<UC> options)
noexcept {
5185 static_assert(is_supported_float_type<T>::value,
5186 "only some floating-point types are supported");
5187 static_assert(is_supported_char_type<UC>::value,
5188 "only char, wchar_t, char16_t and char32_t are supported");
5190 chars_format
const fmt = detail::adjust_for_feature_macros(options.format);
5192 from_chars_result_t<UC> answer;
5193 if (uint64_t(fmt & chars_format::skip_white_space)) {
5194 while ((first != last) && fast_float::is_space(*first)) {
5198 if (first == last) {
5199 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5203 parsed_number_string_t<UC> pns =
5204 uint64_t(fmt & detail::basic_json_fmt)
5205 ? parse_number_string<true, UC>(first, last, options)
5206 : parse_number_string<false, UC>(first, last, options);
5208 if (uint64_t(fmt & chars_format::no_infnan)) {
5209 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5213 return detail::parse_infnan(first, last, value, fmt);
5218 return from_chars_advanced(pns, value);
5221template <
typename T,
typename UC,
typename>
5222FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5223from_chars(UC
const *first, UC
const *last, T &value,
int base)
noexcept {
5225 static_assert(is_supported_integer_type<T>::value,
5226 "only integer types are supported");
5227 static_assert(is_supported_char_type<UC>::value,
5228 "only char, wchar_t, char16_t and char32_t are supported");
5230 parse_options_t<UC> options;
5231 options.base = base;
5232 return from_chars_advanced(first, last, value, options);
5235template <
typename T,
typename UC>
5236FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5237from_chars_int_advanced(UC
const *first, UC
const *last, T &value,
5238 parse_options_t<UC> options)
noexcept {
5240 static_assert(is_supported_integer_type<T>::value,
5241 "only integer types are supported");
5242 static_assert(is_supported_char_type<UC>::value,
5243 "only char, wchar_t, char16_t and char32_t are supported");
5245 chars_format
const fmt = detail::adjust_for_feature_macros(options.format);
5246 int const base = options.base;
5248 from_chars_result_t<UC> answer;
5249 if (uint64_t(fmt & chars_format::skip_white_space)) {
5250 while ((first != last) && fast_float::is_space(*first)) {
5254 if (first == last || base < 2 || base > 36) {
5255 answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5260 return parse_int_string(first, last, value, options);
5263template <
size_t TypeIx>
struct from_chars_advanced_caller {
5264 static_assert(TypeIx > 0,
"unsupported type");
5267template <>
struct from_chars_advanced_caller<1> {
5268 template <
typename T,
typename UC>
5269 FASTFLOAT_CONSTEXPR20
static from_chars_result_t<UC>
5270 call(UC
const *first, UC
const *last, T &value,
5271 parse_options_t<UC> options)
noexcept {
5272 return from_chars_float_advanced(first, last, value, options);
5276template <>
struct from_chars_advanced_caller<2> {
5277 template <
typename T,
typename UC>
5278 FASTFLOAT_CONSTEXPR20
static from_chars_result_t<UC>
5279 call(UC
const *first, UC
const *last, T &value,
5280 parse_options_t<UC> options)
noexcept {
5281 return from_chars_int_advanced(first, last, value, options);
5285template <
typename T,
typename UC>
5286FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5287from_chars_advanced(UC
const *first, UC
const *last, T &value,
5288 parse_options_t<UC> options)
noexcept {
5289 return from_chars_advanced_caller<
5290 size_t(is_supported_float_type<T>::value) +
5291 2 * size_t(is_supported_integer_type<T>::value)>::call(first, last, value,
5303#undef FASTFLOAT_32BIT
5304#undef FASTFLOAT_32BIT_LIMB
5305#undef FASTFLOAT_64BIT
5306#undef FASTFLOAT_64BIT_LIMB
5307#undef FASTFLOAT_ASCII_NUMBER_H
5308#undef FASTFLOAT_ASSERT
5309#undef FASTFLOAT_BIGINT_H
5310#undef FASTFLOAT_CONSTEXPR14
5311#undef FASTFLOAT_CONSTEXPR20
5312#undef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
5313#undef FASTFLOAT_DEBUG_ASSERT
5314#undef FASTFLOAT_DECIMAL_TO_BINARY_H
5315#undef FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
5316#undef FASTFLOAT_DIGIT_COMPARISON_H
5317#undef FASTFLOAT_ENABLE_IF
5318#undef FASTFLOAT_FAST_FLOAT_H
5319#undef FASTFLOAT_FAST_TABLE_H
5320#undef FASTFLOAT_FLOAT_COMMON_H
5321#undef FASTFLOAT_HAS_BIT_CAST
5322#undef FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
5323#undef FASTFLOAT_HAS_SIMD
5324#undef FASTFLOAT_IF_CONSTEXPR17
5325#undef FASTFLOAT_IS_BIG_ENDIAN
5326#undef FASTFLOAT_IS_CONSTEXPR
5327#undef FASTFLOAT_NEON
5328#undef FASTFLOAT_PARSE_NUMBER_H
5329#undef fastfloat_really_inline
5330#undef FASTFLOAT_SIMD_DISABLE_WARNINGS
5331#undef FASTFLOAT_SIMD_RESTORE_WARNINGS
5332#undef FASTFLOAT_SSE2
5333#undef FASTFLOAT_STRINGIZE
5334#undef FASTFLOAT_STRINGIZE_IMPL
5336#undef FASTFLOAT_VERSION
5337#undef FASTFLOAT_VERSION_MAJOR
5338#undef FASTFLOAT_VERSION_MINOR
5339#undef FASTFLOAT_VERSION_PATCH
5340#undef FASTFLOAT_VERSION_STR
5341#undef FASTFLOAT_VISUAL_STUDIO
5347MaterialReader::~MaterialReader() {}
5357#ifndef TINYOBJLOADER_STREAM_READER_MAX_BYTES
5358#define TINYOBJLOADER_STREAM_READER_MAX_BYTES (size_t(256) * size_t(1024) * size_t(1024))
5361 StreamReader(
const char *buf,
size_t length)
5362 : buf_(buf), length_(length), idx_(0), line_num_(1), col_num_(1) {}
5365 StreamReader(
const StreamReader &) ;
5366 StreamReader &operator=(
const StreamReader &) ;
5369 explicit StreamReader(std::istream &is) : buf_(NULL), length_(0), idx_(0), line_num_(1), col_num_(1) {
5370 const size_t max_stream_bytes = TINYOBJLOADER_STREAM_READER_MAX_BYTES;
5371 std::streampos start_pos = is.tellg();
5372 bool can_seek = (start_pos != std::streampos(-1));
5374 is.seekg(0, std::ios::end);
5375 std::streampos end_pos = is.tellg();
5376 if (end_pos >= start_pos) {
5377 std::streamoff remaining_off =
static_cast<std::streamoff
>(end_pos - start_pos);
5378 is.seekg(start_pos);
5379 unsigned long long remaining_ull =
static_cast<unsigned long long>(remaining_off);
5380 if (remaining_ull >
static_cast<unsigned long long>((std::numeric_limits<size_t>::max)())) {
5381 std::stringstream ss;
5382 ss <<
"input stream too large for this platform (" << remaining_ull
5383 <<
" bytes exceeds size_t max " << (std::numeric_limits<size_t>::max)() <<
")\n";
5384 push_error(ss.str());
5389 size_t remaining_size =
static_cast<size_t>(remaining_ull);
5390 if (remaining_size > max_stream_bytes) {
5391 std::stringstream ss;
5392 ss <<
"input stream too large (" << remaining_size
5393 <<
" bytes exceeds limit " << max_stream_bytes <<
" bytes)\n";
5394 push_error(ss.str());
5399 owned_buf_.resize(remaining_size);
5400 if (remaining_size > 0) {
5401 is.read(&owned_buf_[0],
static_cast<std::streamsize
>(remaining_size));
5403 size_t actually_read =
static_cast<size_t>(is.gcount());
5404 owned_buf_.resize(actually_read);
5407 if (!can_seek || owned_buf_.empty()) {
5409 if (can_seek) is.seekg(start_pos);
5411 std::vector<char> content;
5413 size_t total_read = 0;
5415 is.read(chunk, static_cast<std::streamsize>(sizeof(chunk)));
5416 std::streamsize nread = is.gcount();
5417 if (nread <= 0) break;
5418 size_t n = static_cast<size_t>(nread);
5419 if (n > (max_stream_bytes - total_read)) {
5420 std::stringstream ss;
5421 ss <<
"input stream too large (exceeds limit " << max_stream_bytes
5423 push_error(ss.str());
5429 content.insert(content.end(), chunk, chunk + n);
5432 owned_buf_.swap(content);
5434 buf_ = owned_buf_.empty() ?
"" : &owned_buf_[0];
5435 length_ = owned_buf_.size();
5438 bool eof()
const {
return idx_ >= length_; }
5439 size_t tell()
const {
return idx_; }
5440 size_t size()
const {
return length_; }
5441 size_t line_num()
const {
return line_num_; }
5442 size_t col_num()
const {
return col_num_; }
5445 if (idx_ >= length_)
return '\0';
5450 if (idx_ >= length_)
return '\0';
5451 char c = buf_[idx_++];
5452 if (c ==
'\n') { line_num_++; col_num_ = 1; }
else { col_num_++; }
5456 void advance(
size_t n) {
5457 for (
size_t i = 0; i < n && idx_ < length_; i++) {
5458 if (buf_[idx_] ==
'\n') { line_num_++; col_num_ = 1; }
else { col_num_++; }
5464 while (idx_ < length_ && (buf_[idx_] ==
' ' || buf_[idx_] ==
'\t')) {
5470 void skip_space_and_cr() {
5471 while (idx_ < length_ && (buf_[idx_] ==
' ' || buf_[idx_] ==
'\t' || buf_[idx_] ==
'\r')) {
5478 while (idx_ < length_) {
5479 char c = buf_[idx_];
5488 if (idx_ < length_ && buf_[idx_] ==
'\n') {
5500 bool at_line_end()
const {
5501 if (idx_ >= length_)
return true;
5502 char c = buf_[idx_];
5503 return (c ==
'\n' || c ==
'\r' || c ==
'\0');
5506 std::string read_line() {
5508 while (idx_ < length_) {
5509 char c = buf_[idx_];
5510 if (c ==
'\n' || c ==
'\r')
break;
5519 std::string read_token() {
5522 while (idx_ < length_) {
5523 char c = buf_[idx_];
5524 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
5532 bool match(
const char *prefix,
size_t len)
const {
5533 if (idx_ >= length_ || len > length_ - idx_)
return false;
5534 return (memcmp(buf_ + idx_, prefix, len) == 0);
5537 bool char_at(
size_t offset,
char c)
const {
5538 if (idx_ >= length_ || offset >= length_ - idx_)
return false;
5539 return buf_[idx_ + offset] == c;
5542 char peek_at(
size_t offset)
const {
5543 if (idx_ >= length_ || offset >= length_ - idx_)
return '\0';
5544 return buf_[idx_ + offset];
5547 const char *current_ptr()
const {
5548 if (idx_ >= length_)
return "";
5552 size_t remaining()
const {
5553 return (idx_ < length_) ? (length_ - idx_) : 0;
5557 std::string current_line_text()
const {
5559 size_t line_start = idx_;
5560 while (line_start > 0 && buf_[line_start - 1] !=
'\n' && buf_[line_start - 1] !=
'\r') {
5564 size_t line_end = idx_;
5565 while (line_end < length_ && buf_[line_end] !=
'\n' && buf_[line_end] !=
'\r') {
5568 return std::string(buf_ + line_start, line_end - line_start);
5572 std::string format_error(
const std::string &filename,
const std::string &msg)
const {
5573 std::stringstream line_ss, col_ss;
5574 line_ss << line_num_;
5577 result += filename +
":" + line_ss.str() +
":" + col_ss.str() +
": error: " + msg +
"\n";
5578 std::string line_text = current_line_text();
5579 result += line_text +
"\n";
5582 size_t caret_pos = (col_num_ > 0) ? (col_num_ - 1) : 0;
5583 for (
size_t i = 0; i < caret_pos && i < line_text.size(); i++) {
5584 caret += (line_text[i] ==
'\t') ?
'\t' :
' ';
5587 result += caret +
"\n";
5591 std::string format_error(
const std::string &msg)
const {
5592 return format_error(
"<input>", msg);
5596 void push_error(
const std::string &msg) {
5597 errors_.push_back(msg);
5600 void push_formatted_error(
const std::string &filename,
const std::string &msg) {
5601 errors_.push_back(format_error(filename, msg));
5604 bool has_errors()
const {
return !errors_.empty(); }
5606 std::string get_errors()
const {
5608 for (
size_t i = 0; i < errors_.size(); i++) {
5609 result += errors_[i];
5614 const std::vector<std::string> &error_stack()
const {
return errors_; }
5616 void clear_errors() { errors_.clear(); }
5624 std::vector<char> owned_buf_;
5625 std::vector<std::string> errors_;
5628#ifdef TINYOBJLOADER_USE_MMAP
5644 MappedFile() : data(NULL), size(0), is_mapped(false)
5646 , hFile(INVALID_HANDLE_VALUE), hMapping(NULL)
5653 bool open(
const char *filepath) {
5655 std::wstring wfilepath = LongPathW(UTF8ToWchar(std::string(filepath)));
5656 hFile = CreateFileW(wfilepath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
5657 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5658 if (hFile == INVALID_HANDLE_VALUE)
return false;
5659 LARGE_INTEGER fileSize;
5660 if (!GetFileSizeEx(hFile, &fileSize)) { close();
return false; }
5661 if (fileSize.QuadPart < 0) { close();
return false; }
5662 unsigned long long fsize =
static_cast<unsigned long long>(fileSize.QuadPart);
5663 if (fsize >
static_cast<unsigned long long>((std::numeric_limits<size_t>::max)())) {
5667 size =
static_cast<size_t>(fsize);
5668 if (size == 0) { data =
"";
return true; }
5669 hMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
5670 if (hMapping == NULL) { close();
return false; }
5671 data =
static_cast<const char *
>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
5672 if (!data) { close();
return false; }
5676 int fd = ::open(filepath, O_RDONLY);
5677 if (fd == -1)
return false;
5679 if (fstat(fd, &sb) != 0) { ::close(fd);
return false; }
5680 if (sb.st_size < 0) { ::close(fd);
return false; }
5681 if (
static_cast<unsigned long long>(sb.st_size) >
5682 static_cast<unsigned long long>((std::numeric_limits<size_t>::max)())) {
5686 size =
static_cast<size_t>(sb.st_size);
5687 if (size == 0) { ::close(fd); data =
"";
return true; }
5688 mapped_ptr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
5690 if (mapped_ptr == MAP_FAILED) { mapped_ptr = NULL; size = 0;
return false; }
5691 data =
static_cast<const char *
>(mapped_ptr);
5699 if (is_mapped && data) { UnmapViewOfFile(data); }
5702 if (hMapping != NULL) { CloseHandle(hMapping); hMapping = NULL; }
5703 if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; }
5705 if (is_mapped && mapped_ptr && mapped_ptr != MAP_FAILED) { munmap(mapped_ptr, size); }
5713 ~MappedFile() { close(); }
5716 MappedFile(
const MappedFile &);
5717 MappedFile &operator=(
const MappedFile &);
5722struct vertex_index_t {
5723 int v_idx, vt_idx, vn_idx;
5724 vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
5725 explicit vertex_index_t(
int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
5726 vertex_index_t(
int vidx,
int vtidx,
int vnidx)
5727 : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
5736 std::vector<vertex_index_t> vertex_indices;
5738 face_t() : smoothing_group_id(0), pad_(0) {}
5746 std::vector<vertex_index_t> vertex_indices;
5754 std::vector<vertex_index_t> vertex_indices;
5758 tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
5765 std::vector<real_t> v;
5766 std::vector<real_t> vn;
5767 std::vector<real_t> vt;
5773 std::vector<face_t> faceGroup;
5774 std::vector<__line_t> lineGroup;
5775 std::vector<__points_t> pointsGroup;
5780 pointsGroup.clear();
5783 bool IsEmpty()
const {
5784 return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty();
5792#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
5793#define IS_DIGIT(x) \
5794 (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
5795#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
5797template <
typename T>
5798static inline std::string toString(
const T &t) {
5799 std::stringstream ss;
5804static inline std::string removeUtf8Bom(
const std::string& input) {
5806 if (input.size() >= 3 &&
5807 static_cast<unsigned char>(input[0]) == 0xEF &&
5808 static_cast<unsigned char>(input[1]) == 0xBB &&
5809 static_cast<unsigned char>(input[2]) == 0xBF) {
5810 return input.substr(3);
5816static inline std::string trimTrailingWhitespace(
const std::string &s) {
5817 size_t end = s.find_last_not_of(
" \t");
5818 if (end == std::string::npos)
return "";
5819 return s.substr(0, end + 1);
5822struct warning_context {
5825 std::string filename;
5829static inline int size_to_int(
size_t sz) {
5830 return sz >
static_cast<size_t>(INT_MAX) ? INT_MAX : static_cast<int>(sz);
5834static inline bool fixIndex(
int idx,
int n,
int *ret,
bool allow_zero,
5835 const warning_context &context) {
5849 context.filename +
":" + toString(context.line_number) +
5850 ": warning: zero value index found (will have a value of -1 for "
5851 "normal and tex indices)\n";
5869static inline std::string parseString(
const char **token) {
5871 (*token) += strspn((*token),
" \t");
5872 size_t e = strcspn((*token),
" \t\r");
5873 s = std::string((*token), &(*token)[e]);
5878static inline int parseInt(
const char **token) {
5879 (*token) += strspn((*token),
" \t");
5880 int i = atoi((*token));
5881 (*token) += strcspn((*token),
" \t\r");
5885#ifndef TINYOBJLOADER_DISABLE_FAST_FLOAT
5889namespace detail_fp {
5892static inline const char *match_iprefix(
const char *p,
const char *end,
5893 const char *prefix) {
5895 if (p == end)
return NULL;
5898 if (c >=
'A' && c <=
'Z') c += 32;
5899 if (e >=
'A' && e <=
'Z') e += 32;
5900 if (c != e)
return NULL;
5908static inline bool tryParseNanInf(
const char *first,
const char *last,
5909 double *result,
const char **end_ptr) {
5910 if (first >= last)
return false;
5912 const char *p = first;
5913 bool negative =
false;
5918 }
else if (*p ==
'+') {
5922 if (p >= last)
return false;
5925 const char *after = match_iprefix(p, last,
"nan");
5933 after = match_iprefix(p, last,
"infinity");
5935 *result = negative ? std::numeric_limits<double>::lowest()
5936 : (std::numeric_limits<double>::max)();
5941 after = match_iprefix(p, last,
"inf");
5943 *result = negative ? std::numeric_limits<double>::lowest()
5944 : (std::numeric_limits<double>::max)();
5964static bool tryParseDouble(
const char *s,
const char *s_end,
double *result) {
5965 if (!s || !s_end || !result || s >= s_end) {
5971 if (p < s_end && (*p ==
'+' || *p ==
'-')) ++p;
5974 if (fc >=
'A' && fc <=
'Z') fc += 32;
5975 if (fc ==
'n' || fc ==
'i') {
5976 const char *end_ptr;
5977 if (detail_fp::tryParseNanInf(s, s_end, result, &end_ptr)) {
5985 auto r = fast_float::from_chars(s, s_end, tmp,
5986 fast_float::chars_format::general |
5987 fast_float::chars_format::allow_leading_plus);
5988 if (r.ec == tinyobj_ff::ff_errc::ok) {
5997static inline real_t parseReal(
const char **token,
double default_value = 0.0) {
5998 (*token) += strspn((*token),
" \t");
5999 const char *end = (*token) + strcspn((*token),
" \t\r");
6000 double val = default_value;
6001 tryParseDouble((*token), end, &val);
6002 real_t f =
static_cast<real_t
>(val);
6007static inline bool parseReal(
const char **token, real_t *out) {
6008 (*token) += strspn((*token),
" \t");
6009 const char *end = (*token) + strcspn((*token),
" \t\r");
6011 bool ret = tryParseDouble((*token), end, &val);
6013 real_t f =
static_cast<real_t
>(val);
6051static bool tryParseDouble(
const char *s,
const char *s_end,
double *result) {
6056 double mantissa = 0.0;
6069 char exp_sign =
'+';
6070 char const *curr = s;
6075 bool end_not_reached =
false;
6076 bool leading_decimal_dots =
false;
6083 if (*curr ==
'+' || *curr ==
'-') {
6086 if ((curr != s_end) && (*curr ==
'.')) {
6088 leading_decimal_dots =
true;
6090 }
else if (IS_DIGIT(*curr)) {
6091 }
else if (*curr ==
'.') {
6093 leading_decimal_dots =
true;
6099 end_not_reached = (curr != s_end);
6100 if (!leading_decimal_dots) {
6101 while (end_not_reached && IS_DIGIT(*curr)) {
6103 mantissa +=
static_cast<int>(*curr - 0x30);
6106 end_not_reached = (curr != s_end);
6110 if (read == 0)
goto fail;
6114 if (!end_not_reached)
goto assemble;
6120 end_not_reached = (curr != s_end);
6121 while (end_not_reached && IS_DIGIT(*curr)) {
6122 static const double pow_lut[] = {
6123 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001,
6125 const int lut_entries =
sizeof pow_lut /
sizeof pow_lut[0];
6128 mantissa +=
static_cast<int>(*curr - 0x30) *
6129 (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read));
6132 end_not_reached = (curr != s_end);
6134 }
else if (*curr ==
'e' || *curr ==
'E') {
6139 if (!end_not_reached)
goto assemble;
6142 if (*curr ==
'e' || *curr ==
'E') {
6145 end_not_reached = (curr != s_end);
6146 if (end_not_reached && (*curr ==
'+' || *curr ==
'-')) {
6149 }
else if (IS_DIGIT(*curr)) {
6156 end_not_reached = (curr != s_end);
6157 while (end_not_reached && IS_DIGIT(*curr)) {
6161 ((2147483647 - 9) / 10)) {
6166 exponent +=
static_cast<int>(*curr - 0x30);
6169 end_not_reached = (curr != s_end);
6171 exponent *= (exp_sign ==
'+' ? 1 : -1);
6172 if (read == 0)
goto fail;
6176 *result = (sign ==
'+' ? 1 : -1) *
6177 (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
6184static inline real_t parseReal(
const char **token,
double default_value = 0.0) {
6185 (*token) += strspn((*token),
" \t");
6186 const char *end = (*token) + strcspn((*token),
" \t\r");
6187 double val = default_value;
6188 tryParseDouble((*token), end, &val);
6189 real_t f =
static_cast<real_t
>(val);
6194static inline bool parseReal(
const char **token, real_t *out) {
6195 (*token) += strspn((*token),
" \t");
6196 const char *end = (*token) + strcspn((*token),
" \t\r");
6198 bool ret = tryParseDouble((*token), end, &val);
6200 real_t f =
static_cast<real_t
>(val);
6209static inline void parseReal2(real_t *x, real_t *y,
const char **token,
6210 const double default_x = 0.0,
6211 const double default_y = 0.0) {
6212 (*x) = parseReal(token, default_x);
6213 (*y) = parseReal(token, default_y);
6216static inline void parseReal3(real_t *x, real_t *y, real_t *z,
6217 const char **token,
const double default_x = 0.0,
6218 const double default_y = 0.0,
6219 const double default_z = 0.0) {
6220 (*x) = parseReal(token, default_x);
6221 (*y) = parseReal(token, default_y);
6222 (*z) = parseReal(token, default_z);
6226static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w,
6227 const char **token,
const double default_x = 0.0,
6228 const double default_y = 0.0,
6229 const double default_z = 0.0,
6230 const double default_w = 1.0) {
6231 (*x) = parseReal(token, default_x);
6232 (*y) = parseReal(token, default_y);
6233 (*z) = parseReal(token, default_z);
6234 (*w) = parseReal(token, default_w);
6241static inline int parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6242 real_t *r, real_t *g, real_t *b,
6244 const double default_x = 0.0,
6245 const double default_y = 0.0,
6246 const double default_z = 0.0) {
6248 (*x) = parseReal(token, default_x);
6249 (*y) = parseReal(token, default_y);
6250 (*z) = parseReal(token, default_z);
6253 bool has_r = parseReal(token, r);
6256 (*r) = (*g) = (*b) = 1.0;
6260 bool has_g = parseReal(token, g);
6267 bool has_b = parseReal(token, b);
6270 (*r) = (*g) = (*b) = 1.0;
6277static inline bool parseOnOff(
const char **token,
bool default_value =
true) {
6278 (*token) += strspn((*token),
" \t");
6279 const char *end = (*token) + strcspn((*token),
" \t\r");
6281 bool ret = default_value;
6282 if ((0 == strncmp((*token),
"on", 2))) {
6284 }
else if ((0 == strncmp((*token),
"off", 3))) {
6292static inline texture_type_t parseTextureType(
6293 const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) {
6294 (*token) += strspn((*token),
" \t");
6295 const char *end = (*token) + strcspn((*token),
" \t\r");
6296 texture_type_t ty = default_value;
6298 if ((0 == strncmp((*token),
"cube_top", strlen(
"cube_top")))) {
6299 ty = TEXTURE_TYPE_CUBE_TOP;
6300 }
else if ((0 == strncmp((*token),
"cube_bottom", strlen(
"cube_bottom")))) {
6301 ty = TEXTURE_TYPE_CUBE_BOTTOM;
6302 }
else if ((0 == strncmp((*token),
"cube_left", strlen(
"cube_left")))) {
6303 ty = TEXTURE_TYPE_CUBE_LEFT;
6304 }
else if ((0 == strncmp((*token),
"cube_right", strlen(
"cube_right")))) {
6305 ty = TEXTURE_TYPE_CUBE_RIGHT;
6306 }
else if ((0 == strncmp((*token),
"cube_front", strlen(
"cube_front")))) {
6307 ty = TEXTURE_TYPE_CUBE_FRONT;
6308 }
else if ((0 == strncmp((*token),
"cube_back", strlen(
"cube_back")))) {
6309 ty = TEXTURE_TYPE_CUBE_BACK;
6310 }
else if ((0 == strncmp((*token),
"sphere", strlen(
"sphere")))) {
6311 ty = TEXTURE_TYPE_SPHERE;
6318static tag_sizes parseTagTriple(
const char **token) {
6321 (*token) += strspn((*token),
" \t");
6322 ts.num_ints = atoi((*token));
6323 (*token) += strcspn((*token),
"/ \t\r");
6324 if ((*token)[0] !=
'/') {
6330 (*token) += strspn((*token),
" \t");
6331 ts.num_reals = atoi((*token));
6332 (*token) += strcspn((*token),
"/ \t\r");
6333 if ((*token)[0] !=
'/') {
6338 ts.num_strings = parseInt(token);
6344static bool parseTriple(
const char **token,
int vsize,
int vnsize,
int vtsize,
6345 vertex_index_t *ret,
const warning_context &context) {
6350 vertex_index_t vi(-1);
6352 if (!fixIndex(atoi((*token)), vsize, &vi.v_idx,
false, context)) {
6356 (*token) += strcspn((*token),
"/ \t\r");
6357 if ((*token)[0] !=
'/') {
6364 if ((*token)[0] ==
'/') {
6366 if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx,
true, context)) {
6369 (*token) += strcspn((*token),
"/ \t\r");
6375 if (!fixIndex(atoi((*token)), vtsize, &vi.vt_idx,
true, context)) {
6379 (*token) += strcspn((*token),
"/ \t\r");
6380 if ((*token)[0] !=
'/') {
6387 if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx,
true, context)) {
6390 (*token) += strcspn((*token),
"/ \t\r");
6398static vertex_index_t parseRawTriple(
const char **token) {
6399 vertex_index_t vi(
static_cast<int>(0));
6401 vi.v_idx = atoi((*token));
6402 (*token) += strcspn((*token),
"/ \t\r");
6403 if ((*token)[0] !=
'/') {
6409 if ((*token)[0] ==
'/') {
6411 vi.vn_idx = atoi((*token));
6412 (*token) += strcspn((*token),
"/ \t\r");
6417 vi.vt_idx = atoi((*token));
6418 (*token) += strcspn((*token),
"/ \t\r");
6419 if ((*token)[0] !=
'/') {
6425 vi.vn_idx = atoi((*token));
6426 (*token) += strcspn((*token),
"/ \t\r");
6432static inline std::string sr_parseString(StreamReader &sr) {
6437 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6444static inline int sr_parseInt(StreamReader &sr) {
6446 const char *start = sr.current_ptr();
6447 size_t rem = sr.remaining();
6450 char c = start[len];
6451 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6457 size_t copy_len = len < 63 ? len : 63;
6458 if (copy_len != len) {
6462 memcpy(tmp, start, copy_len);
6463 tmp[copy_len] =
'\0';
6465 char *endptr = NULL;
6466 long val = strtol(tmp, &endptr, 10);
6467 const bool has_error =
6468 (errno == ERANGE || endptr == tmp ||
6469 val > (std::numeric_limits<int>::max)() ||
6470 val < (std::numeric_limits<int>::min)());
6472 i =
static_cast<int>(val);
6479static inline real_t sr_parseReal(StreamReader &sr,
double default_value = 0.0) {
6481 const char *start = sr.current_ptr();
6482 size_t rem = sr.remaining();
6485 char c = start[len];
6486 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6489 double val = default_value;
6491 tryParseDouble(start, start + len, &val);
6494 return static_cast<real_t
>(val);
6497static inline bool sr_parseReal(StreamReader &sr, real_t *out) {
6499 const char *start = sr.current_ptr();
6500 size_t rem = sr.remaining();
6503 char c = start[len];
6504 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6507 if (len == 0)
return false;
6509 bool ret = tryParseDouble(start, start + len, &val);
6511 (*out) =
static_cast<real_t
>(val);
6517static inline void sr_parseReal2(real_t *x, real_t *y, StreamReader &sr,
6518 const double default_x = 0.0,
6519 const double default_y = 0.0) {
6520 (*x) = sr_parseReal(sr, default_x);
6521 (*y) = sr_parseReal(sr, default_y);
6524static inline void sr_parseReal3(real_t *x, real_t *y, real_t *z,
6526 const double default_x = 0.0,
6527 const double default_y = 0.0,
6528 const double default_z = 0.0) {
6529 (*x) = sr_parseReal(sr, default_x);
6530 (*y) = sr_parseReal(sr, default_y);
6531 (*z) = sr_parseReal(sr, default_z);
6534static inline int sr_parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6535 real_t *r, real_t *g, real_t *b,
6537 const double default_x = 0.0,
6538 const double default_y = 0.0,
6539 const double default_z = 0.0) {
6540 (*x) = sr_parseReal(sr, default_x);
6541 (*y) = sr_parseReal(sr, default_y);
6542 (*z) = sr_parseReal(sr, default_z);
6544 bool has_r = sr_parseReal(sr, r);
6546 (*r) = (*g) = (*b) = 1.0;
6550 bool has_g = sr_parseReal(sr, g);
6556 bool has_b = sr_parseReal(sr, b);
6558 (*r) = (*g) = (*b) = 1.0;
6570static inline bool sr_parseInt(StreamReader &sr,
int *out, std::string *err,
6571 const std::string &filename) {
6573 const char *start = sr.current_ptr();
6574 size_t rem = sr.remaining();
6577 char c = start[len];
6578 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6583 (*err) += sr.format_error(filename,
"expected integer value");
6589 size_t copy_len = len < 63 ? len : 63;
6590 memcpy(tmp, start, copy_len);
6591 tmp[copy_len] =
'\0';
6592 if (copy_len != len) {
6594 (*err) += sr.format_error(filename,
"integer value too long");
6601 char *endptr = NULL;
6602 long val = strtol(tmp, &endptr, 10);
6603 if (errno == ERANGE || val > (std::numeric_limits<int>::max)() ||
6604 val < (std::numeric_limits<int>::min)()) {
6606 (*err) += sr.format_error(filename,
6607 "integer value out of range, got '" + std::string(tmp) +
"'");
6613 if (endptr == tmp || (*endptr !=
'\0' && *endptr !=
' ' && *endptr !=
'\t')) {
6615 (*err) += sr.format_error(filename,
6616 "expected integer, got '" + std::string(tmp) +
"'");
6622 *out =
static_cast<int>(val);
6627static inline bool sr_parseReal(StreamReader &sr, real_t *out,
6628 double default_value,
6630 const std::string &filename) {
6632 const char *start = sr.current_ptr();
6633 size_t rem = sr.remaining();
6636 char c = start[len];
6637 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'\0')
break;
6642 *out =
static_cast<real_t
>(default_value);
6646 if (!tryParseDouble(start, start + len, &val)) {
6649 size_t copy_len = len < 63 ? len : 63;
6650 memcpy(tmp, start, copy_len);
6651 tmp[copy_len] =
'\0';
6652 (*err) += sr.format_error(filename,
6653 "expected number, got '" + std::string(tmp) +
"'");
6655 *out =
static_cast<real_t
>(default_value);
6659 *out =
static_cast<real_t
>(val);
6664static inline bool sr_parseReal2(real_t *x, real_t *y, StreamReader &sr,
6666 const std::string &filename,
6667 const double default_x = 0.0,
6668 const double default_y = 0.0) {
6669 if (!sr_parseReal(sr, x, default_x, err, filename))
return false;
6670 if (!sr_parseReal(sr, y, default_y, err, filename))
return false;
6674static inline bool sr_parseReal3(real_t *x, real_t *y, real_t *z,
6677 const std::string &filename,
6678 const double default_x = 0.0,
6679 const double default_y = 0.0,
6680 const double default_z = 0.0) {
6681 if (!sr_parseReal(sr, x, default_x, err, filename))
return false;
6682 if (!sr_parseReal(sr, y, default_y, err, filename))
return false;
6683 if (!sr_parseReal(sr, z, default_z, err, filename))
return false;
6688static inline int sr_parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6689 real_t *r, real_t *g, real_t *b,
6692 const std::string &filename,
6693 const double default_x = 0.0,
6694 const double default_y = 0.0,
6695 const double default_z = 0.0) {
6696 if (!sr_parseReal(sr, x, default_x, err, filename))
return -1;
6697 if (!sr_parseReal(sr, y, default_y, err, filename))
return -1;
6698 if (!sr_parseReal(sr, z, default_z, err, filename))
return -1;
6700 bool has_r = sr_parseReal(sr, r);
6702 (*r) = (*g) = (*b) = 1.0;
6706 bool has_g = sr_parseReal(sr, g);
6712 bool has_b = sr_parseReal(sr, b);
6714 (*r) = (*g) = (*b) = 1.0;
6721static inline int sr_parseIntNoSkip(StreamReader &sr);
6724static inline void sr_skipTagField(StreamReader &sr) {
6725 while (!sr.eof() && !sr.at_line_end() && !IS_SPACE(sr.peek()) &&
6731static tag_sizes sr_parseTagTriple(StreamReader &sr) {
6735 ts.num_ints = sr_parseIntNoSkip(sr);
6736 sr_skipTagField(sr);
6737 if (!sr.eof() && sr.peek() ==
'/') {
6740 ts.num_reals = sr_parseIntNoSkip(sr);
6741 sr_skipTagField(sr);
6742 if (!sr.eof() && sr.peek() ==
'/') {
6744 ts.num_strings = sr_parseInt(sr);
6750static inline int sr_parseIntNoSkip(StreamReader &sr) {
6751 const char *start = sr.current_ptr();
6752 size_t rem = sr.remaining();
6754 if (len < rem && (start[len] ==
'+' || start[len] ==
'-')) len++;
6755 while (len < rem && start[len] >=
'0' && start[len] <=
'9') len++;
6759 size_t copy_len = len < 63 ? len : 63;
6760 if (copy_len != len) {
6764 memcpy(tmp, start, copy_len);
6765 tmp[copy_len] =
'\0';
6767 char *endptr = NULL;
6768 long val = strtol(tmp, &endptr, 10);
6769 if (errno == 0 && endptr != tmp && *endptr ==
'\0' &&
6770 val <= (std::numeric_limits<int>::max)() &&
6771 val >= (std::numeric_limits<int>::min)()) {
6772 i =
static_cast<int>(val);
6779static inline void sr_skipUntil(StreamReader &sr,
const char *delims) {
6782 for (
const char *d = delims; *d; d++) {
6783 if (c == *d)
return;
6789static bool sr_parseTriple(StreamReader &sr,
int vsize,
int vnsize,
int vtsize,
6790 vertex_index_t *ret,
const warning_context &context) {
6791 if (!ret)
return false;
6793 vertex_index_t vi(-1);
6796 if (!fixIndex(sr_parseIntNoSkip(sr), vsize, &vi.v_idx,
false, context)) {
6800 sr_skipUntil(sr,
"/ \t\r\n");
6801 if (sr.eof() || sr.peek() !=
'/') {
6808 if (!sr.eof() && sr.peek() ==
'/') {
6810 if (!fixIndex(sr_parseIntNoSkip(sr), vnsize, &vi.vn_idx,
true, context)) {
6813 sr_skipUntil(sr,
"/ \t\r\n");
6819 if (!fixIndex(sr_parseIntNoSkip(sr), vtsize, &vi.vt_idx,
true, context)) {
6823 sr_skipUntil(sr,
"/ \t\r\n");
6824 if (sr.eof() || sr.peek() !=
'/') {
6831 if (!fixIndex(sr_parseIntNoSkip(sr), vnsize, &vi.vn_idx,
true, context)) {
6834 sr_skipUntil(sr,
"/ \t\r\n");
6840static vertex_index_t sr_parseRawTriple(StreamReader &sr) {
6841 vertex_index_t vi(
static_cast<int>(0));
6844 vi.v_idx = sr_parseIntNoSkip(sr);
6845 sr_skipUntil(sr,
"/ \t\r\n");
6846 if (sr.eof() || sr.peek() !=
'/')
return vi;
6850 if (!sr.eof() && sr.peek() ==
'/') {
6852 vi.vn_idx = sr_parseIntNoSkip(sr);
6853 sr_skipUntil(sr,
"/ \t\r\n");
6858 vi.vt_idx = sr_parseIntNoSkip(sr);
6859 sr_skipUntil(sr,
"/ \t\r\n");
6860 if (sr.eof() || sr.peek() !=
'/')
return vi;
6863 vi.vn_idx = sr_parseIntNoSkip(sr);
6864 sr_skipUntil(sr,
"/ \t\r\n");
6868bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt,
6869 const char *linebuf) {
6871 bool found_texname =
false;
6872 std::string texture_name;
6874 const char *token = linebuf;
6876 while (!IS_NEW_LINE((*token))) {
6877 token += strspn(token,
" \t");
6878 if ((0 == strncmp(token,
"-blendu", 7)) && IS_SPACE((token[7]))) {
6880 texopt->blendu = parseOnOff(&token,
true);
6881 }
else if ((0 == strncmp(token,
"-blendv", 7)) && IS_SPACE((token[7]))) {
6883 texopt->blendv = parseOnOff(&token,
true);
6884 }
else if ((0 == strncmp(token,
"-clamp", 6)) && IS_SPACE((token[6]))) {
6886 texopt->clamp = parseOnOff(&token,
true);
6887 }
else if ((0 == strncmp(token,
"-boost", 6)) && IS_SPACE((token[6]))) {
6889 texopt->sharpness = parseReal(&token, 1.0);
6890 }
else if ((0 == strncmp(token,
"-bm", 3)) && IS_SPACE((token[3]))) {
6892 texopt->bump_multiplier = parseReal(&token, 1.0);
6893 }
else if ((0 == strncmp(token,
"-o", 2)) && IS_SPACE((token[2]))) {
6895 parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]),
6896 &(texopt->origin_offset[2]), &token);
6897 }
else if ((0 == strncmp(token,
"-s", 2)) && IS_SPACE((token[2]))) {
6899 parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]),
6900 &token, 1.0, 1.0, 1.0);
6901 }
else if ((0 == strncmp(token,
"-t", 2)) && IS_SPACE((token[2]))) {
6903 parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]),
6904 &(texopt->turbulence[2]), &token);
6905 }
else if ((0 == strncmp(token,
"-type", 5)) && IS_SPACE((token[5]))) {
6907 texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE);
6908 }
else if ((0 == strncmp(token,
"-texres", 7)) && IS_SPACE((token[7]))) {
6911 texopt->texture_resolution = parseInt(&token);
6912 }
else if ((0 == strncmp(token,
"-imfchan", 8)) && IS_SPACE((token[8]))) {
6914 token += strspn(token,
" \t");
6915 const char *end = token + strcspn(token,
" \t\r");
6916 if ((end - token) == 1) {
6917 texopt->imfchan = (*token);
6920 }
else if ((0 == strncmp(token,
"-mm", 3)) && IS_SPACE((token[3]))) {
6922 parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
6923 }
else if ((0 == strncmp(token,
"-colorspace", 11)) &&
6924 IS_SPACE((token[11]))) {
6926 texopt->colorspace = parseString(&token);
6930 size_t len = strcspn(token,
" \t\r");
6931 texture_name = std::string(token, token + len);
6934 token += strspn(token,
" \t");
6938 texture_name = std::string(token);
6939 token += texture_name.length();
6942 found_texname =
true;
6946 if (found_texname) {
6947 (*texname) = texture_name;
6954static void InitTexOpt(texture_option_t *texopt,
const bool is_bump) {
6956 texopt->imfchan =
'l';
6958 texopt->imfchan =
'm';
6960 texopt->bump_multiplier =
static_cast<real_t
>(1.0);
6961 texopt->clamp =
false;
6962 texopt->blendu =
true;
6963 texopt->blendv =
true;
6964 texopt->sharpness =
static_cast<real_t
>(1.0);
6965 texopt->brightness =
static_cast<real_t
>(0.0);
6966 texopt->contrast =
static_cast<real_t
>(1.0);
6967 texopt->origin_offset[0] =
static_cast<real_t
>(0.0);
6968 texopt->origin_offset[1] =
static_cast<real_t
>(0.0);
6969 texopt->origin_offset[2] =
static_cast<real_t
>(0.0);
6970 texopt->scale[0] =
static_cast<real_t
>(1.0);
6971 texopt->scale[1] =
static_cast<real_t
>(1.0);
6972 texopt->scale[2] =
static_cast<real_t
>(1.0);
6973 texopt->turbulence[0] =
static_cast<real_t
>(0.0);
6974 texopt->turbulence[1] =
static_cast<real_t
>(0.0);
6975 texopt->turbulence[2] =
static_cast<real_t
>(0.0);
6976 texopt->texture_resolution = -1;
6977 texopt->type = TEXTURE_TYPE_NONE;
6980static void InitMaterial(material_t *material) {
6981 InitTexOpt(&material->ambient_texopt,
false);
6982 InitTexOpt(&material->diffuse_texopt,
false);
6983 InitTexOpt(&material->specular_texopt,
false);
6984 InitTexOpt(&material->specular_highlight_texopt,
false);
6985 InitTexOpt(&material->bump_texopt,
true);
6986 InitTexOpt(&material->displacement_texopt,
false);
6987 InitTexOpt(&material->alpha_texopt,
false);
6988 InitTexOpt(&material->reflection_texopt,
false);
6989 InitTexOpt(&material->roughness_texopt,
false);
6990 InitTexOpt(&material->metallic_texopt,
false);
6991 InitTexOpt(&material->sheen_texopt,
false);
6992 InitTexOpt(&material->emissive_texopt,
false);
6993 InitTexOpt(&material->normal_texopt,
6995 material->name =
"";
6996 material->ambient_texname =
"";
6997 material->diffuse_texname =
"";
6998 material->specular_texname =
"";
6999 material->specular_highlight_texname =
"";
7000 material->bump_texname =
"";
7001 material->displacement_texname =
"";
7002 material->reflection_texname =
"";
7003 material->alpha_texname =
"";
7004 for (
int i = 0; i < 3; i++) {
7005 material->ambient[i] =
static_cast<real_t
>(0.0);
7006 material->diffuse[i] =
static_cast<real_t
>(0.0);
7007 material->specular[i] =
static_cast<real_t
>(0.0);
7008 material->transmittance[i] =
static_cast<real_t
>(0.0);
7009 material->emission[i] =
static_cast<real_t
>(0.0);
7011 material->illum = 0;
7012 material->dissolve =
static_cast<real_t
>(1.0);
7013 material->shininess =
static_cast<real_t
>(1.0);
7014 material->ior =
static_cast<real_t
>(1.0);
7016 material->roughness =
static_cast<real_t
>(0.0);
7017 material->metallic =
static_cast<real_t
>(0.0);
7018 material->sheen =
static_cast<real_t
>(0.0);
7019 material->clearcoat_thickness =
static_cast<real_t
>(0.0);
7020 material->clearcoat_roughness =
static_cast<real_t
>(0.0);
7021 material->anisotropy_rotation =
static_cast<real_t
>(0.0);
7022 material->anisotropy =
static_cast<real_t
>(0.0);
7023 material->roughness_texname =
"";
7024 material->metallic_texname =
"";
7025 material->sheen_texname =
"";
7026 material->emissive_texname =
"";
7027 material->normal_texname =
"";
7029 material->unknown_parameter.clear();
7033template <
typename T>
7034static int pnpoly(
int nvert, T *vertx, T *verty, T testx, T testy) {
7036 for (i = 0, j = nvert - 1; i < nvert; j = i++) {
7037 if (((verty[i] > testy) != (verty[j] > testy)) &&
7039 (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) +
7046struct TinyObjPoint {
7048 TinyObjPoint() : x(0), y(0), z(0) {}
7049 TinyObjPoint(real_t x_, real_t y_, real_t z_) : x(x_), y(y_), z(z_) {}
7052inline TinyObjPoint cross(
const TinyObjPoint &v1,
const TinyObjPoint &v2) {
7053 return TinyObjPoint(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z,
7054 v1.x * v2.y - v1.y * v2.x);
7057inline real_t dot(
const TinyObjPoint &v1,
const TinyObjPoint &v2) {
7058 return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
7061inline real_t GetLength(TinyObjPoint &e) {
7062 return std::sqrt(e.x * e.x + e.y * e.y + e.z * e.z);
7065inline TinyObjPoint Normalize(TinyObjPoint e) {
7066 real_t len = GetLength(e);
7067 if (len <= real_t(0))
return TinyObjPoint(real_t(0), real_t(0), real_t(0));
7068 real_t inv_length = real_t(1) / len;
7069 return TinyObjPoint(e.x * inv_length, e.y * inv_length, e.z * inv_length);
7072inline TinyObjPoint WorldToLocal(
const TinyObjPoint &a,
const TinyObjPoint &u,
7073 const TinyObjPoint &v,
const TinyObjPoint &w) {
7074 return TinyObjPoint(dot(a, u), dot(a, v), dot(a, w));
7078static bool exportGroupsToShape(shape_t *shape,
const PrimGroup &prim_group,
7079 const std::vector<tag_t> &tags,
7080 const int material_id,
const std::string &name,
7081 bool triangulate,
const std::vector<real_t> &v,
7082 std::string *warn) {
7083 if (prim_group.IsEmpty()) {
7090 if (!prim_group.faceGroup.empty()) {
7092 for (
size_t i = 0; i < prim_group.faceGroup.size(); i++) {
7093 const face_t &face = prim_group.faceGroup[i];
7095 size_t npolys = face.vertex_indices.size();
7100 (*warn) +=
"Degenerated face found\n.";
7105 if (triangulate && npolys != 3) {
7107 vertex_index_t i0 = face.vertex_indices[0];
7108 vertex_index_t i1 = face.vertex_indices[1];
7109 vertex_index_t i2 = face.vertex_indices[2];
7110 vertex_index_t i3 = face.vertex_indices[3];
7112 if (i0.v_idx < 0 || i1.v_idx < 0 || i2.v_idx < 0 || i3.v_idx < 0) {
7114 (*warn) +=
"Face with invalid vertex index found.\n";
7119 size_t vi0 = size_t(i0.v_idx);
7120 size_t vi1 = size_t(i1.v_idx);
7121 size_t vi2 = size_t(i2.v_idx);
7122 size_t vi3 = size_t(i3.v_idx);
7124 if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
7125 ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) {
7129 (*warn) +=
"Face with invalid vertex index found.\n";
7134 real_t v0x = v[vi0 * 3 + 0];
7135 real_t v0y = v[vi0 * 3 + 1];
7136 real_t v0z = v[vi0 * 3 + 2];
7137 real_t v1x = v[vi1 * 3 + 0];
7138 real_t v1y = v[vi1 * 3 + 1];
7139 real_t v1z = v[vi1 * 3 + 2];
7140 real_t v2x = v[vi2 * 3 + 0];
7141 real_t v2y = v[vi2 * 3 + 1];
7142 real_t v2z = v[vi2 * 3 + 2];
7143 real_t v3x = v[vi3 * 3 + 0];
7144 real_t v3y = v[vi3 * 3 + 1];
7145 real_t v3z = v[vi3 * 3 + 2];
7165 real_t e02x = v2x - v0x;
7166 real_t e02y = v2y - v0y;
7167 real_t e02z = v2z - v0z;
7168 real_t e13x = v3x - v1x;
7169 real_t e13y = v3y - v1y;
7170 real_t e13z = v3z - v1z;
7172 real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z;
7173 real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z;
7175 index_t idx0, idx1, idx2, idx3;
7177 idx0.vertex_index = i0.v_idx;
7178 idx0.normal_index = i0.vn_idx;
7179 idx0.texcoord_index = i0.vt_idx;
7180 idx1.vertex_index = i1.v_idx;
7181 idx1.normal_index = i1.vn_idx;
7182 idx1.texcoord_index = i1.vt_idx;
7183 idx2.vertex_index = i2.v_idx;
7184 idx2.normal_index = i2.vn_idx;
7185 idx2.texcoord_index = i2.vt_idx;
7186 idx3.vertex_index = i3.v_idx;
7187 idx3.normal_index = i3.vn_idx;
7188 idx3.texcoord_index = i3.vt_idx;
7190 if (sqr02 < sqr13) {
7192 shape->mesh.indices.push_back(idx0);
7193 shape->mesh.indices.push_back(idx1);
7194 shape->mesh.indices.push_back(idx2);
7196 shape->mesh.indices.push_back(idx0);
7197 shape->mesh.indices.push_back(idx2);
7198 shape->mesh.indices.push_back(idx3);
7201 shape->mesh.indices.push_back(idx0);
7202 shape->mesh.indices.push_back(idx1);
7203 shape->mesh.indices.push_back(idx3);
7205 shape->mesh.indices.push_back(idx1);
7206 shape->mesh.indices.push_back(idx2);
7207 shape->mesh.indices.push_back(idx3);
7211 shape->mesh.num_face_vertices.push_back(3);
7212 shape->mesh.num_face_vertices.push_back(3);
7214 shape->mesh.material_ids.push_back(material_id);
7215 shape->mesh.material_ids.push_back(material_id);
7217 shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
7218 shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
7221#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
7224 bool valid_poly =
true;
7225 for (
size_t k = 0; k < npolys; ++k) {
7226 size_t vi = size_t(face.vertex_indices[k].v_idx);
7227 if ((3 * vi + 2) >= v.size()) {
7234 (*warn) +=
"Face with invalid vertex index found.\n";
7240 vertex_index_t i0 = face.vertex_indices[0];
7241 vertex_index_t i0_2 = i0;
7246 for (
size_t k = 0; k < npolys; ++k) {
7247 i0 = face.vertex_indices[k % npolys];
7248 size_t vi0 = size_t(i0.v_idx);
7250 size_t j = (k + 1) % npolys;
7251 i0_2 = face.vertex_indices[j];
7252 size_t vi0_2 = size_t(i0_2.v_idx);
7254 real_t v0x = v[vi0 * 3 + 0];
7255 real_t v0y = v[vi0 * 3 + 1];
7256 real_t v0z = v[vi0 * 3 + 2];
7258 real_t v0x_2 = v[vi0_2 * 3 + 0];
7259 real_t v0y_2 = v[vi0_2 * 3 + 1];
7260 real_t v0z_2 = v[vi0_2 * 3 + 2];
7262 const TinyObjPoint point1(v0x, v0y, v0z);
7263 const TinyObjPoint point2(v0x_2, v0y_2, v0z_2);
7265 TinyObjPoint a(point1.x - point2.x, point1.y - point2.y,
7266 point1.z - point2.z);
7267 TinyObjPoint b(point1.x + point2.x, point1.y + point2.y,
7268 point1.z + point2.z);
7274 real_t length_n = GetLength(n);
7276 if (length_n <= 0) {
7280 real_t inv_length = -real_t(1.0) / length_n;
7285 TinyObjPoint axis_w, axis_v, axis_u;
7288 if (std::fabs(axis_w.x) > real_t(0.9999999)) {
7289 a = TinyObjPoint(0, 1, 0);
7291 a = TinyObjPoint(1, 0, 0);
7293 axis_v = Normalize(cross(axis_w, a));
7294 axis_u = cross(axis_w, axis_v);
7295 using Point = std::array<real_t, 2>;
7299 std::vector<std::vector<Point> > polygon;
7301 std::vector<Point> polyline;
7308 for (
size_t k = 0; k < npolys; k++) {
7309 i0 = face.vertex_indices[k];
7310 size_t vi0 = size_t(i0.v_idx);
7312 assert(((3 * vi0 + 2) < v.size()));
7314 real_t v0x = v[vi0 * 3 + 0];
7315 real_t v0y = v[vi0 * 3 + 1];
7316 real_t v0z = v[vi0 * 3 + 2];
7318 TinyObjPoint polypoint(v0x, v0y, v0z);
7319 TinyObjPoint loc = WorldToLocal(polypoint, axis_u, axis_v, axis_w);
7321 polyline.push_back({loc.x, loc.y});
7324 polygon.push_back(polyline);
7325 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
7328 assert(indices.size() % 3 == 0);
7331 for (
size_t k = 0; k < indices.size() / 3; k++) {
7333 index_t idx0, idx1, idx2;
7334 idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx;
7336 face.vertex_indices[indices[3 * k + 0]].vn_idx;
7337 idx0.texcoord_index =
7338 face.vertex_indices[indices[3 * k + 0]].vt_idx;
7339 idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx;
7341 face.vertex_indices[indices[3 * k + 1]].vn_idx;
7342 idx1.texcoord_index =
7343 face.vertex_indices[indices[3 * k + 1]].vt_idx;
7344 idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx;
7346 face.vertex_indices[indices[3 * k + 2]].vn_idx;
7347 idx2.texcoord_index =
7348 face.vertex_indices[indices[3 * k + 2]].vt_idx;
7350 shape->mesh.indices.push_back(idx0);
7351 shape->mesh.indices.push_back(idx1);
7352 shape->mesh.indices.push_back(idx2);
7354 shape->mesh.num_face_vertices.push_back(3);
7355 shape->mesh.material_ids.push_back(material_id);
7356 shape->mesh.smoothing_group_ids.push_back(
7357 face.smoothing_group_id);
7362 vertex_index_t i0 = face.vertex_indices[0];
7363 vertex_index_t i1(-1);
7364 vertex_index_t i2 = face.vertex_indices[1];
7367 size_t axes[2] = {1, 2};
7368 for (
size_t k = 0; k < npolys; ++k) {
7369 i0 = face.vertex_indices[(k + 0) % npolys];
7370 i1 = face.vertex_indices[(k + 1) % npolys];
7371 i2 = face.vertex_indices[(k + 2) % npolys];
7372 size_t vi0 = size_t(i0.v_idx);
7373 size_t vi1 = size_t(i1.v_idx);
7374 size_t vi2 = size_t(i2.v_idx);
7376 if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
7377 ((3 * vi2 + 2) >= v.size())) {
7382 real_t v0x = v[vi0 * 3 + 0];
7383 real_t v0y = v[vi0 * 3 + 1];
7384 real_t v0z = v[vi0 * 3 + 2];
7385 real_t v1x = v[vi1 * 3 + 0];
7386 real_t v1y = v[vi1 * 3 + 1];
7387 real_t v1z = v[vi1 * 3 + 2];
7388 real_t v2x = v[vi2 * 3 + 0];
7389 real_t v2y = v[vi2 * 3 + 1];
7390 real_t v2z = v[vi2 * 3 + 2];
7391 real_t e0x = v1x - v0x;
7392 real_t e0y = v1y - v0y;
7393 real_t e0z = v1z - v0z;
7394 real_t e1x = v2x - v1x;
7395 real_t e1y = v2y - v1y;
7396 real_t e1z = v2z - v1z;
7397 real_t cx = std::fabs(e0y * e1z - e0z * e1y);
7398 real_t cy = std::fabs(e0z * e1x - e0x * e1z);
7399 real_t cz = std::fabs(e0x * e1y - e0y * e1x);
7400 const real_t epsilon = std::numeric_limits<real_t>::epsilon();
7403 if (cx > epsilon || cy > epsilon || cz > epsilon) {
7406 if (cx > cy && cx > cz) {
7411 if (cz > cx && cz > cy) {
7420 face_t remainingFace = face;
7421 size_t guess_vert = 0;
7422 vertex_index_t ind[3];
7428 size_t remainingIterations = face.vertex_indices.size();
7429 size_t previousRemainingVertices =
7430 remainingFace.vertex_indices.size();
7432 while (remainingFace.vertex_indices.size() > 3 &&
7433 remainingIterations > 0) {
7437 npolys = remainingFace.vertex_indices.size();
7438 if (guess_vert >= npolys) {
7439 guess_vert -= npolys;
7442 if (previousRemainingVertices != npolys) {
7444 previousRemainingVertices = npolys;
7445 remainingIterations = npolys;
7449 remainingIterations--;
7452 for (
size_t k = 0; k < 3; k++) {
7453 ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
7454 size_t vi = size_t(ind[k].v_idx);
7455 if (((vi * 3 + axes[0]) >= v.size()) ||
7456 ((vi * 3 + axes[1]) >= v.size())) {
7458 vx[k] =
static_cast<real_t
>(0.0);
7459 vy[k] =
static_cast<real_t
>(0.0);
7461 vx[k] = v[vi * 3 + axes[0]];
7462 vy[k] = v[vi * 3 + axes[1]];
7469 real_t e0x = vx[1] - vx[0];
7470 real_t e0y = vy[1] - vy[0];
7471 real_t e1x = vx[2] - vx[1];
7472 real_t e1y = vy[2] - vy[1];
7473 real_t cross = e0x * e1y - e0y * e1x;
7479 (vx[0] * vy[1] - vy[0] * vx[1]) *
static_cast<real_t
>(0.5);
7482 if (cross * area <
static_cast<real_t
>(0.0)) {
7490 bool overlap =
false;
7491 for (
size_t otherVert = 3; otherVert < npolys; ++otherVert) {
7492 size_t idx = (guess_vert + otherVert) % npolys;
7494 if (idx >= remainingFace.vertex_indices.size()) {
7500 size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
7502 if (((ovi * 3 + axes[0]) >= v.size()) ||
7503 ((ovi * 3 + axes[1]) >= v.size())) {
7508 real_t tx = v[ovi * 3 + axes[0]];
7509 real_t ty = v[ovi * 3 + axes[1]];
7510 if (pnpoly(3, vx, vy, tx, ty)) {
7525 index_t idx0, idx1, idx2;
7526 idx0.vertex_index = ind[0].v_idx;
7527 idx0.normal_index = ind[0].vn_idx;
7528 idx0.texcoord_index = ind[0].vt_idx;
7529 idx1.vertex_index = ind[1].v_idx;
7530 idx1.normal_index = ind[1].vn_idx;
7531 idx1.texcoord_index = ind[1].vt_idx;
7532 idx2.vertex_index = ind[2].v_idx;
7533 idx2.normal_index = ind[2].vn_idx;
7534 idx2.texcoord_index = ind[2].vt_idx;
7536 shape->mesh.indices.push_back(idx0);
7537 shape->mesh.indices.push_back(idx1);
7538 shape->mesh.indices.push_back(idx2);
7540 shape->mesh.num_face_vertices.push_back(3);
7541 shape->mesh.material_ids.push_back(material_id);
7542 shape->mesh.smoothing_group_ids.push_back(
7543 face.smoothing_group_id);
7547 size_t removed_vert_index = (guess_vert + 1) % npolys;
7548 while (removed_vert_index + 1 < npolys) {
7549 remainingFace.vertex_indices[removed_vert_index] =
7550 remainingFace.vertex_indices[removed_vert_index + 1];
7551 removed_vert_index += 1;
7553 remainingFace.vertex_indices.pop_back();
7558 if (remainingFace.vertex_indices.size() == 3) {
7559 i0 = remainingFace.vertex_indices[0];
7560 i1 = remainingFace.vertex_indices[1];
7561 i2 = remainingFace.vertex_indices[2];
7563 index_t idx0, idx1, idx2;
7564 idx0.vertex_index = i0.v_idx;
7565 idx0.normal_index = i0.vn_idx;
7566 idx0.texcoord_index = i0.vt_idx;
7567 idx1.vertex_index = i1.v_idx;
7568 idx1.normal_index = i1.vn_idx;
7569 idx1.texcoord_index = i1.vt_idx;
7570 idx2.vertex_index = i2.v_idx;
7571 idx2.normal_index = i2.vn_idx;
7572 idx2.texcoord_index = i2.vt_idx;
7574 shape->mesh.indices.push_back(idx0);
7575 shape->mesh.indices.push_back(idx1);
7576 shape->mesh.indices.push_back(idx2);
7578 shape->mesh.num_face_vertices.push_back(3);
7579 shape->mesh.material_ids.push_back(material_id);
7580 shape->mesh.smoothing_group_ids.push_back(
7581 face.smoothing_group_id);
7587 for (
size_t k = 0; k < npolys; k++) {
7589 idx.vertex_index = face.vertex_indices[k].v_idx;
7590 idx.normal_index = face.vertex_indices[k].vn_idx;
7591 idx.texcoord_index = face.vertex_indices[k].vt_idx;
7592 shape->mesh.indices.push_back(idx);
7595 shape->mesh.num_face_vertices.push_back(
7596 static_cast<unsigned int>(npolys));
7597 shape->mesh.material_ids.push_back(material_id);
7598 shape->mesh.smoothing_group_ids.push_back(
7599 face.smoothing_group_id);
7603 shape->mesh.tags = tags;
7607 if (!prim_group.lineGroup.empty()) {
7609 for (
size_t i = 0; i < prim_group.lineGroup.size(); i++) {
7610 for (
size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size();
7612 const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j];
7615 idx.vertex_index = vi.v_idx;
7616 idx.normal_index = vi.vn_idx;
7617 idx.texcoord_index = vi.vt_idx;
7619 shape->lines.indices.push_back(idx);
7622 shape->lines.num_line_vertices.push_back(
7623 int(prim_group.lineGroup[i].vertex_indices.size()));
7628 if (!prim_group.pointsGroup.empty()) {
7630 for (
size_t i = 0; i < prim_group.pointsGroup.size(); i++) {
7631 for (
size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size();
7633 const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j];
7636 idx.vertex_index = vi.v_idx;
7637 idx.normal_index = vi.vn_idx;
7638 idx.texcoord_index = vi.vt_idx;
7640 shape->points.indices.push_back(idx);
7650static void SplitString(
const std::string &s,
char delim,
char escape,
7651 std::vector<std::string> &elems) {
7654 bool escaping =
false;
7655 for (
size_t i = 0; i < s.size(); ++i) {
7659 }
else if (ch == escape) {
7660 if ((i + 1) < s.size()) {
7661 const char next = s[i + 1];
7662 if ((next == delim) || (next == escape)) {
7667 }
else if (ch == delim) {
7668 if (!token.empty()) {
7669 elems.push_back(token);
7677 elems.push_back(token);
7680static void RemoveEmptyTokens(std::vector<std::string> *tokens) {
7681 if (!tokens)
return;
7683 const std::vector<std::string> &src = *tokens;
7684 std::vector<std::string> filtered;
7685 filtered.reserve(src.size());
7686 for (
size_t i = 0; i < src.size(); i++) {
7687 if (!src[i].empty()) {
7688 filtered.push_back(src[i]);
7691 tokens->swap(filtered);
7694static std::string JoinPath(
const std::string &dir,
7695 const std::string &filename) {
7700 char lastChar = *dir.rbegin();
7701 if (lastChar !=
'/') {
7702 return dir + std::string(
"/") + filename;
7704 return dir + filename;
7709static bool LoadMtlInternal(std::map<std::string, int> *material_map,
7710 std::vector<material_t> *materials,
7712 std::string *warning, std::string *err,
7713 const std::string &filename =
"<stream>") {
7714 if (sr.has_errors()) {
7716 (*err) += sr.get_errors();
7721 material_t material;
7722 InitMaterial(&material);
7726 bool has_tr =
false;
7730 bool has_kd =
false;
7732 std::stringstream warn_ss;
7735 if (sr.remaining() >= 3 &&
7736 static_cast<unsigned char>(sr.peek()) == 0xEF &&
7737 static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
7738 static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
7744 if (sr.at_line_end()) { sr.skip_line();
continue; }
7745 if (sr.peek() ==
'#') { sr.skip_line();
continue; }
7747 size_t line_num = sr.line_num();
7750 if (sr.match(
"newmtl", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7752 if (!material.name.empty()) {
7753 material_map->insert(std::pair<std::string, int>(
7754 material.name,
static_cast<int>(materials->size())));
7755 materials->push_back(material);
7758 InitMaterial(&material);
7766 std::string namebuf = sr_parseString(sr);
7767 if (namebuf.empty()) {
7769 (*warning) +=
"empty material name in `newmtl`\n";
7772 material.name = namebuf;
7779 if (sr.peek() ==
'K' && sr.peek_at(1) ==
'a' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7782 if (!sr_parseReal3(&r, &g, &b, sr, err, filename))
return false;
7783 material.ambient[0] = r;
7784 material.ambient[1] = g;
7785 material.ambient[2] = b;
7791 if (sr.peek() ==
'K' && sr.peek_at(1) ==
'd' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7794 if (!sr_parseReal3(&r, &g, &b, sr, err, filename))
return false;
7795 material.diffuse[0] = r;
7796 material.diffuse[1] = g;
7797 material.diffuse[2] = b;
7804 if (sr.peek() ==
'K' && sr.peek_at(1) ==
's' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7807 if (!sr_parseReal3(&r, &g, &b, sr, err, filename))
return false;
7808 material.specular[0] = r;
7809 material.specular[1] = g;
7810 material.specular[2] = b;
7816 if ((sr.peek() ==
'K' && sr.peek_at(1) ==
't' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) ||
7817 (sr.peek() ==
'T' && sr.peek_at(1) ==
'f' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t'))) {
7820 if (!sr_parseReal3(&r, &g, &b, sr, err, filename))
return false;
7821 material.transmittance[0] = r;
7822 material.transmittance[1] = g;
7823 material.transmittance[2] = b;
7829 if (sr.peek() ==
'N' && sr.peek_at(1) ==
'i' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7831 if (!sr_parseReal(sr, &material.ior, 0.0, err, filename))
return false;
7837 if (sr.peek() ==
'K' && sr.peek_at(1) ==
'e' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7840 if (!sr_parseReal3(&r, &g, &b, sr, err, filename))
return false;
7841 material.emission[0] = r;
7842 material.emission[1] = g;
7843 material.emission[2] = b;
7849 if (sr.peek() ==
'N' && sr.peek_at(1) ==
's' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7851 if (!sr_parseReal(sr, &material.shininess, 0.0, err, filename))
return false;
7857 if (sr.match(
"illum", 5) && (sr.peek_at(5) ==
' ' || sr.peek_at(5) ==
'\t')) {
7859 if (!sr_parseInt(sr, &material.illum, err, filename))
return false;
7865 if (sr.peek() ==
'd' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
7867 if (!sr_parseReal(sr, &material.dissolve, 0.0, err, filename))
return false;
7870 warn_ss <<
"Both `d` and `Tr` parameters defined for \""
7872 <<
"\". Use the value of `d` for dissolve (line " << line_num
7879 if (sr.peek() ==
'T' && sr.peek_at(1) ==
'r' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7882 warn_ss <<
"Both `d` and `Tr` parameters defined for \""
7884 <<
"\". Use the value of `d` for dissolve (line " << line_num
7888 if (!sr_parseReal(sr, &tr_val, 0.0, err, filename))
return false;
7889 material.dissolve =
static_cast<real_t
>(1.0) - tr_val;
7897 if (sr.peek() ==
'P' && sr.peek_at(1) ==
'r' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7899 if (!sr_parseReal(sr, &material.roughness, 0.0, err, filename))
return false;
7905 if (sr.peek() ==
'P' && sr.peek_at(1) ==
'm' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7907 if (!sr_parseReal(sr, &material.metallic, 0.0, err, filename))
return false;
7913 if (sr.peek() ==
'P' && sr.peek_at(1) ==
's' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7915 if (!sr_parseReal(sr, &material.sheen, 0.0, err, filename))
return false;
7921 if (sr.peek() ==
'P' && sr.peek_at(1) ==
'c' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
7923 if (!sr_parseReal(sr, &material.clearcoat_thickness, 0.0, err, filename))
return false;
7929 if (sr.match(
"Pcr", 3) && (sr.peek_at(3) ==
' ' || sr.peek_at(3) ==
'\t')) {
7931 if (!sr_parseReal(sr, &material.clearcoat_roughness, 0.0, err, filename))
return false;
7937 if (sr.match(
"aniso", 5) && (sr.peek_at(5) ==
' ' || sr.peek_at(5) ==
'\t')) {
7939 if (!sr_parseReal(sr, &material.anisotropy, 0.0, err, filename))
return false;
7945 if (sr.match(
"anisor", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7947 if (!sr_parseReal(sr, &material.anisotropy_rotation, 0.0, err, filename))
return false;
7956 if (sr.match(
"map_Ka", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7958 std::string line_rest = trimTrailingWhitespace(sr.read_line());
7959 ParseTextureNameAndOption(&(material.ambient_texname),
7960 &(material.ambient_texopt), line_rest.c_str());
7966 if (sr.match(
"map_Kd", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7968 std::string line_rest = trimTrailingWhitespace(sr.read_line());
7969 ParseTextureNameAndOption(&(material.diffuse_texname),
7970 &(material.diffuse_texopt), line_rest.c_str());
7972 material.diffuse[0] =
static_cast<real_t
>(0.6);
7973 material.diffuse[1] =
static_cast<real_t
>(0.6);
7974 material.diffuse[2] =
static_cast<real_t
>(0.6);
7981 if (sr.match(
"map_Ks", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7983 std::string line_rest = trimTrailingWhitespace(sr.read_line());
7984 ParseTextureNameAndOption(&(material.specular_texname),
7985 &(material.specular_texopt), line_rest.c_str());
7991 if (sr.match(
"map_Ns", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
7993 std::string line_rest = trimTrailingWhitespace(sr.read_line());
7994 ParseTextureNameAndOption(&(material.specular_highlight_texname),
7995 &(material.specular_highlight_texopt), line_rest.c_str());
8001 if ((sr.match(
"map_bump", 8) || sr.match(
"map_Bump", 8)) &&
8002 (sr.peek_at(8) ==
' ' || sr.peek_at(8) ==
'\t')) {
8004 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8005 ParseTextureNameAndOption(&(material.bump_texname),
8006 &(material.bump_texopt), line_rest.c_str());
8012 if (sr.match(
"bump", 4) && (sr.peek_at(4) ==
' ' || sr.peek_at(4) ==
'\t')) {
8014 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8015 ParseTextureNameAndOption(&(material.bump_texname),
8016 &(material.bump_texopt), line_rest.c_str());
8022 if (sr.match(
"map_d", 5) && (sr.peek_at(5) ==
' ' || sr.peek_at(5) ==
'\t')) {
8024 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8025 ParseTextureNameAndOption(&(material.alpha_texname),
8026 &(material.alpha_texopt), line_rest.c_str());
8032 if ((sr.match(
"map_disp", 8) || sr.match(
"map_Disp", 8)) &&
8033 (sr.peek_at(8) ==
' ' || sr.peek_at(8) ==
'\t')) {
8035 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8036 ParseTextureNameAndOption(&(material.displacement_texname),
8037 &(material.displacement_texopt), line_rest.c_str());
8043 if (sr.match(
"disp", 4) && (sr.peek_at(4) ==
' ' || sr.peek_at(4) ==
'\t')) {
8045 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8046 ParseTextureNameAndOption(&(material.displacement_texname),
8047 &(material.displacement_texopt), line_rest.c_str());
8053 if (sr.match(
"refl", 4) && (sr.peek_at(4) ==
' ' || sr.peek_at(4) ==
'\t')) {
8055 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8056 ParseTextureNameAndOption(&(material.reflection_texname),
8057 &(material.reflection_texopt), line_rest.c_str());
8063 if (sr.match(
"map_Pr", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8065 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8066 ParseTextureNameAndOption(&(material.roughness_texname),
8067 &(material.roughness_texopt), line_rest.c_str());
8073 if (sr.match(
"map_Pm", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8075 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8076 ParseTextureNameAndOption(&(material.metallic_texname),
8077 &(material.metallic_texopt), line_rest.c_str());
8083 if (sr.match(
"map_Ps", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8085 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8086 ParseTextureNameAndOption(&(material.sheen_texname),
8087 &(material.sheen_texopt), line_rest.c_str());
8093 if (sr.match(
"map_Ke", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8095 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8096 ParseTextureNameAndOption(&(material.emissive_texname),
8097 &(material.emissive_texopt), line_rest.c_str());
8103 if (sr.match(
"norm", 4) && (sr.peek_at(4) ==
' ' || sr.peek_at(4) ==
'\t')) {
8105 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8106 ParseTextureNameAndOption(&(material.normal_texname),
8107 &(material.normal_texopt), line_rest.c_str());
8114 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8115 const char *_lp = line_rest.c_str();
8116 const char *_space = strchr(_lp,
' ');
8118 _space = strchr(_lp,
'\t');
8121 std::ptrdiff_t len = _space - _lp;
8122 std::string key(_lp,
static_cast<size_t>(len));
8123 std::string value = _space + 1;
8124 material.unknown_parameter.insert(
8125 std::pair<std::string, std::string>(key, value));
8131 if (!material.name.empty()) {
8132 material_map->insert(std::pair<std::string, int>(
8133 material.name,
static_cast<int>(materials->size())));
8134 materials->push_back(material);
8138 (*warning) += warn_ss.str();
8144void LoadMtl(std::map<std::string, int> *material_map,
8145 std::vector<material_t> *materials, std::istream *inStream,
8146 std::string *warning, std::string *err) {
8147 StreamReader sr(*inStream);
8148 LoadMtlInternal(material_map, materials, sr, warning, err);
8152bool MaterialFileReader::operator()(
const std::string &matId,
8153 std::vector<material_t> *materials,
8154 std::map<std::string, int> *matMap,
8155 std::string *warn, std::string *err) {
8156 if (!m_mtlBaseDir.empty()) {
8164 std::vector<std::string> paths;
8165 std::istringstream f(m_mtlBaseDir);
8168 while (getline(f, s, sep)) {
8172 for (
size_t i = 0; i < paths.size(); i++) {
8173 std::string filepath = JoinPath(paths[i], matId);
8175#ifdef TINYOBJLOADER_USE_MMAP
8178 if (!mf.open(filepath.c_str()))
continue;
8179 if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8181 std::stringstream ss;
8182 ss <<
"input stream too large (" << mf.size
8183 <<
" bytes exceeds limit "
8184 << TINYOBJLOADER_STREAM_READER_MAX_BYTES <<
" bytes)\n";
8189 StreamReader sr(mf.data, mf.size);
8190 return LoadMtlInternal(matMap, materials, sr, warn, err, filepath);
8194 std::ifstream matIStream(LongPathW(UTF8ToWchar(filepath)).c_str());
8196 std::ifstream matIStream(filepath.c_str());
8199 StreamReader mtl_sr(matIStream);
8200 return LoadMtlInternal(matMap, materials, mtl_sr, warn, err, filepath);
8205 std::stringstream ss;
8206 ss <<
"Material file [ " << matId
8207 <<
" ] not found in a path : " << m_mtlBaseDir <<
"\n";
8209 (*warn) += ss.str();
8214 std::string filepath = matId;
8216#ifdef TINYOBJLOADER_USE_MMAP
8219 if (mf.open(filepath.c_str())) {
8220 if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8222 std::stringstream ss;
8223 ss <<
"input stream too large (" << mf.size
8224 <<
" bytes exceeds limit "
8225 << TINYOBJLOADER_STREAM_READER_MAX_BYTES <<
" bytes)\n";
8230 StreamReader sr(mf.data, mf.size);
8231 return LoadMtlInternal(matMap, materials, sr, warn, err, filepath);
8236 std::ifstream matIStream(LongPathW(UTF8ToWchar(filepath)).c_str());
8238 std::ifstream matIStream(filepath.c_str());
8241 StreamReader mtl_sr(matIStream);
8242 return LoadMtlInternal(matMap, materials, mtl_sr, warn, err, filepath);
8246 std::stringstream ss;
8247 ss <<
"Material file [ " << filepath
8248 <<
" ] not found in a path : " << m_mtlBaseDir <<
"\n";
8250 (*warn) += ss.str();
8257bool MaterialStreamReader::operator()(
const std::string &matId,
8258 std::vector<material_t> *materials,
8259 std::map<std::string, int> *matMap,
8260 std::string *warn, std::string *err) {
8263 std::stringstream ss;
8264 ss <<
"Material stream in error state. \n";
8266 (*warn) += ss.str();
8271 StreamReader mtl_sr(m_inStream);
8272 return LoadMtlInternal(matMap, materials, mtl_sr, warn, err,
"<stream>");
8275static bool LoadObjInternal(attrib_t *attrib, std::vector<shape_t> *shapes,
8276 std::vector<material_t> *materials,
8277 std::string *warn, std::string *err,
8279 MaterialReader *readMatFn,
bool triangulate,
8280 bool default_vcols_fallback,
8281 const std::string &filename =
"<stream>") {
8282 if (sr.has_errors()) {
8284 (*err) += sr.get_errors();
8289 std::vector<real_t> v;
8290 std::vector<real_t> vertex_weights;
8291 std::vector<real_t> vn;
8292 std::vector<real_t> vt;
8293 std::vector<real_t> vt_w;
8294 std::vector<real_t> vc;
8295 std::vector<skin_weight_t> vw;
8296 std::vector<tag_t> tags;
8297 PrimGroup prim_group;
8301 std::set<std::string> material_filenames;
8302 std::map<std::string, int> material_map;
8305 unsigned int current_smoothing_id = 0;
8307 int greatest_v_idx = -1;
8308 int greatest_vn_idx = -1;
8309 int greatest_vt_idx = -1;
8313 bool found_all_colors =
true;
8316 if (sr.remaining() >= 3 &&
8317 static_cast<unsigned char>(sr.peek()) == 0xEF &&
8318 static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
8319 static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
8323 warning_context context;
8324 context.warn = warn;
8325 context.filename = filename;
8329 if (sr.at_line_end()) { sr.skip_line();
continue; }
8330 if (sr.peek() ==
'#') { sr.skip_line();
continue; }
8332 size_t line_num = sr.line_num();
8335 if (sr.peek() ==
'v' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8340 int num_components = sr_parseVertexWithColor(&x, &y, &z, &r, &g, &b, sr, err, filename);
8341 if (num_components < 0)
return false;
8342 found_all_colors &= (num_components == 6);
8348 vertex_weights.push_back(r);
8350 if ((num_components == 6) || default_vcols_fallback) {
8361 if (sr.peek() ==
'v' && sr.peek_at(1) ==
'n' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
8364 if (!sr_parseReal3(&x, &y, &z, sr, err, filename))
return false;
8373 if (sr.peek() ==
'v' && sr.peek_at(1) ==
't' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
8376 if (!sr_parseReal2(&x, &y, sr, err, filename))
return false;
8381 real_t w =
static_cast<real_t
>(0.0);
8382 sr_parseReal(sr, &w);
8390 if (sr.peek() ==
'v' && sr.peek_at(1) ==
'w' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
8394 if (!sr_parseInt(sr, &vid, err, filename))
return false;
8399 size_t vw_loop_max = sr.remaining() + 1;
8400 size_t vw_loop_iter = 0;
8401 while (!sr.at_line_end() && sr.peek() !=
'#' &&
8402 vw_loop_iter < vw_loop_max) {
8404 sr_parseReal2(&j, &w, sr, -1.0);
8406 if (j <
static_cast<real_t
>(0)) {
8408 (*err) += sr.format_error(filename,
8409 "failed to parse `vw' line: joint_id is negative");
8414 joint_and_weight_t jw;
8415 jw.joint_id = int(j);
8418 sw.weightValues.push_back(jw);
8419 sr.skip_space_and_cr();
8428 context.line_number = line_num;
8431 if (sr.peek() ==
'l' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8436 size_t l_loop_max = sr.remaining() + 1;
8437 size_t l_loop_iter = 0;
8438 while (!sr.at_line_end() && sr.peek() !=
'#' &&
8439 l_loop_iter < l_loop_max) {
8441 if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8442 size_to_int(vn.size() / 3),
8443 size_to_int(vt.size() / 2), &vi, context)) {
8445 (*err) += sr.format_error(filename,
8446 "failed to parse `l' line (invalid vertex index)");
8451 line.vertex_indices.push_back(vi);
8452 sr.skip_space_and_cr();
8456 prim_group.lineGroup.push_back(line);
8462 if (sr.peek() ==
'p' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8467 size_t p_loop_max = sr.remaining() + 1;
8468 size_t p_loop_iter = 0;
8469 while (!sr.at_line_end() && sr.peek() !=
'#' &&
8470 p_loop_iter < p_loop_max) {
8472 if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8473 size_to_int(vn.size() / 3),
8474 size_to_int(vt.size() / 2), &vi, context)) {
8476 (*err) += sr.format_error(filename,
8477 "failed to parse `p' line (invalid vertex index)");
8482 pts.vertex_indices.push_back(vi);
8483 sr.skip_space_and_cr();
8487 prim_group.pointsGroup.push_back(pts);
8493 if (sr.peek() ==
'f' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8499 face.smoothing_group_id = current_smoothing_id;
8500 face.vertex_indices.reserve(3);
8502 size_t f_loop_max = sr.remaining() + 1;
8503 size_t f_loop_iter = 0;
8504 while (!sr.at_line_end() && sr.peek() !=
'#' &&
8505 f_loop_iter < f_loop_max) {
8507 if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8508 size_to_int(vn.size() / 3),
8509 size_to_int(vt.size() / 2), &vi, context)) {
8511 (*err) += sr.format_error(filename,
8512 "failed to parse `f' line (invalid vertex index)");
8517 greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx;
8519 greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx;
8521 greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx;
8523 face.vertex_indices.push_back(vi);
8524 sr.skip_space_and_cr();
8528 prim_group.faceGroup.push_back(face);
8534 if (sr.match(
"usemtl", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8536 std::string namebuf = sr_parseString(sr);
8538 int newMaterialId = -1;
8539 std::map<std::string, int>::const_iterator it =
8540 material_map.find(namebuf);
8541 if (it != material_map.end()) {
8542 newMaterialId = it->second;
8545 (*warn) +=
"material [ '" + namebuf +
"' ] not found in .mtl\n";
8549 if (newMaterialId != material) {
8550 exportGroupsToShape(&shape, prim_group, tags, material, name,
8551 triangulate, v, warn);
8552 prim_group.faceGroup.clear();
8553 material = newMaterialId;
8561 if (sr.match(
"mtllib", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
8565 std::string line_rest = trimTrailingWhitespace(sr.read_line());
8566 std::vector<std::string> filenames;
8567 SplitString(line_rest,
' ',
'\\', filenames);
8568 RemoveEmptyTokens(&filenames);
8570 if (filenames.empty()) {
8572 std::stringstream ss;
8573 ss <<
"Looks like empty filename for mtllib. Use default "
8575 << line_num <<
".)\n";
8577 (*warn) += ss.str();
8581 for (
size_t s = 0; s < filenames.size(); s++) {
8582 if (material_filenames.count(filenames[s]) > 0) {
8587 std::string warn_mtl;
8588 std::string err_mtl;
8589 bool ok = (*readMatFn)(filenames[s].c_str(), materials,
8590 &material_map, &warn_mtl, &err_mtl);
8591 if (warn && (!warn_mtl.empty())) {
8592 (*warn) += warn_mtl;
8595 if (err && (!err_mtl.empty())) {
8601 material_filenames.insert(filenames[s]);
8609 "Failed to load material file(s). Use default "
8621 if (sr.peek() ==
'g' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8623 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8624 triangulate, v, warn);
8627 if (shape.mesh.indices.size() > 0) {
8628 shapes->push_back(shape);
8636 std::vector<std::string> names;
8638 size_t g_loop_max = sr.remaining() + 1;
8639 size_t g_loop_iter = 0;
8640 while (!sr.at_line_end() && sr.peek() !=
'#' &&
8641 g_loop_iter < g_loop_max) {
8642 std::string str = sr_parseString(sr);
8643 names.push_back(str);
8644 sr.skip_space_and_cr();
8650 if (names.size() < 2) {
8653 std::stringstream ss;
8654 ss <<
"Empty group name. line: " << line_num <<
"\n";
8655 (*warn) += ss.str();
8659 std::stringstream ss;
8662 for (
size_t i = 2; i < names.size(); i++) {
8663 ss <<
" " << names[i];
8674 if (sr.peek() ==
'o' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8676 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8677 triangulate, v, warn);
8680 if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 ||
8681 shape.points.indices.size() > 0) {
8682 shapes->push_back(shape);
8690 std::string rest = sr.read_line();
8697 if (sr.peek() ==
't' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8698 const int max_tag_nums = 8192;
8703 tag.name = sr_parseString(sr);
8705 tag_sizes ts = sr_parseTagTriple(sr);
8707 if (ts.num_ints < 0) {
8710 if (ts.num_ints > max_tag_nums) {
8711 ts.num_ints = max_tag_nums;
8714 if (ts.num_reals < 0) {
8717 if (ts.num_reals > max_tag_nums) {
8718 ts.num_reals = max_tag_nums;
8721 if (ts.num_strings < 0) {
8724 if (ts.num_strings > max_tag_nums) {
8725 ts.num_strings = max_tag_nums;
8728 tag.intValues.resize(
static_cast<size_t>(ts.num_ints));
8730 for (
size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
8731 tag.intValues[i] = sr_parseInt(sr);
8734 tag.floatValues.resize(
static_cast<size_t>(ts.num_reals));
8735 for (
size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
8736 tag.floatValues[i] = sr_parseReal(sr);
8739 tag.stringValues.resize(
static_cast<size_t>(ts.num_strings));
8740 for (
size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
8741 tag.stringValues[i] = sr_parseString(sr);
8744 tags.push_back(tag);
8750 if (sr.peek() ==
's' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8755 if (sr.at_line_end()) {
8760 if (sr.peek() ==
'\r') {
8765 if (sr.remaining() >= 3 && sr.match(
"off", 3)) {
8766 current_smoothing_id = 0;
8768 int smGroupId = sr_parseInt(sr);
8769 if (smGroupId < 0) {
8770 current_smoothing_id = 0;
8772 current_smoothing_id =
static_cast<unsigned int>(smGroupId);
8785 if (!found_all_colors && !default_vcols_fallback) {
8789 if (greatest_v_idx >= size_to_int(v.size() / 3)) {
8791 std::stringstream ss;
8792 ss <<
"Vertex indices out of bounds (line " << sr.line_num() <<
".)\n\n";
8793 (*warn) += ss.str();
8796 if (greatest_vn_idx >= size_to_int(vn.size() / 3)) {
8798 std::stringstream ss;
8799 ss <<
"Vertex normal indices out of bounds (line " << sr.line_num()
8801 (*warn) += ss.str();
8804 if (greatest_vt_idx >= size_to_int(vt.size() / 2)) {
8806 std::stringstream ss;
8807 ss <<
"Vertex texcoord indices out of bounds (line " << sr.line_num()
8809 (*warn) += ss.str();
8813 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8814 triangulate, v, warn);
8815 if (ret || shape.mesh.indices.size()) {
8816 shapes->push_back(shape);
8820 attrib->vertices.swap(v);
8821 attrib->vertex_weights.swap(vertex_weights);
8822 attrib->normals.swap(vn);
8823 attrib->texcoords.swap(vt);
8824 attrib->texcoord_ws.swap(vt_w);
8825 attrib->colors.swap(vc);
8826 attrib->skin_weights.swap(vw);
8831bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
8832 std::vector<material_t> *materials, std::string *warn,
8833 std::string *err,
const char *filename,
const char *mtl_basedir,
8834 bool triangulate,
bool default_vcols_fallback) {
8835 attrib->vertices.clear();
8836 attrib->vertex_weights.clear();
8837 attrib->normals.clear();
8838 attrib->texcoords.clear();
8839 attrib->texcoord_ws.clear();
8840 attrib->colors.clear();
8841 attrib->skin_weights.clear();
8844 std::string baseDir = mtl_basedir ? mtl_basedir :
"";
8845 if (!baseDir.empty()) {
8847 const char dirsep =
'/';
8849 const char dirsep =
'\\';
8851 if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep;
8853 MaterialFileReader matFileReader(baseDir);
8855#ifdef TINYOBJLOADER_USE_MMAP
8858 if (!mf.open(filename)) {
8860 std::stringstream ss;
8861 ss <<
"Cannot open file [" << filename <<
"]\n";
8866 if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8868 std::stringstream ss;
8869 ss <<
"input stream too large (" << mf.size
8870 <<
" bytes exceeds limit "
8871 << TINYOBJLOADER_STREAM_READER_MAX_BYTES <<
" bytes)\n";
8876 StreamReader sr(mf.data, mf.size);
8877 return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8878 &matFileReader, triangulate, default_vcols_fallback,
8883 std::ifstream ifs(LongPathW(UTF8ToWchar(filename)).c_str());
8885 std::ifstream ifs(filename);
8889 std::stringstream ss;
8890 ss <<
"Cannot open file [" << filename <<
"]\n";
8896 StreamReader sr(ifs);
8897 return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8898 &matFileReader, triangulate, default_vcols_fallback,
8904bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
8905 std::vector<material_t> *materials, std::string *warn,
8906 std::string *err, std::istream *inStream,
8907 MaterialReader *readMatFn ,
bool triangulate,
8908 bool default_vcols_fallback) {
8909 attrib->vertices.clear();
8910 attrib->vertex_weights.clear();
8911 attrib->normals.clear();
8912 attrib->texcoords.clear();
8913 attrib->texcoord_ws.clear();
8914 attrib->colors.clear();
8915 attrib->skin_weights.clear();
8918 StreamReader sr(*inStream);
8919 return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8920 readMatFn, triangulate, default_vcols_fallback);
8924static bool LoadObjWithCallbackInternal(StreamReader &sr,
8925 const callback_t &callback,
8927 MaterialReader *readMatFn,
8930 if (sr.has_errors()) {
8932 (*err) += sr.get_errors();
8938 std::set<std::string> material_filenames;
8939 std::map<std::string, int> material_map;
8940 int material_id = -1;
8942 std::vector<index_t> indices;
8943 std::vector<material_t> materials;
8944 std::vector<std::string> names;
8946 std::vector<const char *> names_out;
8949 if (sr.remaining() >= 3 &&
8950 static_cast<unsigned char>(sr.peek()) == 0xEF &&
8951 static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
8952 static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
8958 if (sr.at_line_end()) { sr.skip_line();
continue; }
8959 if (sr.peek() ==
'#') { sr.skip_line();
continue; }
8962 if (sr.peek() ==
'v' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
8967 int num_components = sr_parseVertexWithColor(&x, &y, &z, &r, &g, &b, sr, err, std::string());
8968 if (num_components < 0) {
8971 if (callback.vertex_cb) {
8972 callback.vertex_cb(user_data, x, y, z, r);
8974 if (callback.vertex_color_cb) {
8975 bool found_color = (num_components == 6);
8976 callback.vertex_color_cb(user_data, x, y, z, r, g, b, found_color);
8983 if (sr.peek() ==
'v' && sr.peek_at(1) ==
'n' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
8986 sr_parseReal3(&x, &y, &z, sr);
8987 if (callback.normal_cb) {
8988 callback.normal_cb(user_data, x, y, z);
8995 if (sr.peek() ==
'v' && sr.peek_at(1) ==
't' && (sr.peek_at(2) ==
' ' || sr.peek_at(2) ==
'\t')) {
8998 sr_parseReal3(&x, &y, &z, sr);
8999 if (callback.texcoord_cb) {
9000 callback.texcoord_cb(user_data, x, y, z);
9007 if (sr.peek() ==
'f' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
9012 size_t cf_loop_max = sr.remaining() + 1;
9013 size_t cf_loop_iter = 0;
9014 while (!sr.at_line_end() && sr.peek() !=
'#' &&
9015 cf_loop_iter < cf_loop_max) {
9016 vertex_index_t vi = sr_parseRawTriple(sr);
9019 idx.vertex_index = vi.v_idx;
9020 idx.normal_index = vi.vn_idx;
9021 idx.texcoord_index = vi.vt_idx;
9023 indices.push_back(idx);
9024 sr.skip_space_and_cr();
9028 if (callback.index_cb && indices.size() > 0) {
9029 callback.index_cb(user_data, &indices.at(0),
9030 static_cast<int>(indices.size()));
9038 if (sr.match(
"usemtl", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
9040 std::string namebuf = sr_parseString(sr);
9042 int newMaterialId = -1;
9043 std::map<std::string, int>::const_iterator it =
9044 material_map.find(namebuf);
9045 if (it != material_map.end()) {
9046 newMaterialId = it->second;
9048 if (warn && (!callback.usemtl_cb)) {
9049 (*warn) +=
"material [ " + namebuf +
" ] not found in .mtl\n";
9053 if (newMaterialId != material_id) {
9054 material_id = newMaterialId;
9057 if (callback.usemtl_cb) {
9058 callback.usemtl_cb(user_data, namebuf.c_str(), material_id);
9066 if (sr.match(
"mtllib", 6) && (sr.peek_at(6) ==
' ' || sr.peek_at(6) ==
'\t')) {
9070 std::string line_rest = trimTrailingWhitespace(sr.read_line());
9071 std::vector<std::string> filenames;
9072 SplitString(line_rest,
' ',
'\\', filenames);
9073 RemoveEmptyTokens(&filenames);
9075 if (filenames.empty()) {
9078 "Looks like empty filename for mtllib. Use default "
9083 for (
size_t s = 0; s < filenames.size(); s++) {
9084 if (material_filenames.count(filenames[s]) > 0) {
9089 std::string warn_mtl;
9090 std::string err_mtl;
9091 bool ok = (*readMatFn)(filenames[s].c_str(), &materials,
9092 &material_map, &warn_mtl, &err_mtl);
9094 if (warn && (!warn_mtl.empty())) {
9095 (*warn) += warn_mtl;
9098 if (err && (!err_mtl.empty())) {
9104 material_filenames.insert(filenames[s]);
9112 "Failed to load material file(s). Use default "
9116 if (callback.mtllib_cb && !materials.empty()) {
9117 callback.mtllib_cb(user_data, &materials.at(0),
9118 static_cast<int>(materials.size()));
9129 if (sr.peek() ==
'g' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
9132 size_t cg_loop_max = sr.remaining() + 1;
9133 size_t cg_loop_iter = 0;
9134 while (!sr.at_line_end() && sr.peek() !=
'#' &&
9135 cg_loop_iter < cg_loop_max) {
9136 std::string str = sr_parseString(sr);
9137 names.push_back(str);
9138 sr.skip_space_and_cr();
9142 assert(names.size() > 0);
9144 if (callback.group_cb) {
9145 if (names.size() > 1) {
9146 names_out.resize(names.size() - 1);
9147 for (
size_t j = 0; j < names_out.size(); j++) {
9148 names_out[j] = names[j + 1].c_str();
9150 callback.group_cb(user_data, &names_out.at(0),
9151 static_cast<int>(names_out.size()));
9154 callback.group_cb(user_data, NULL, 0);
9163 if (sr.peek() ==
'o' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
9165 std::string object_name = sr.read_line();
9167 if (callback.object_cb) {
9168 callback.object_cb(user_data, object_name.c_str());
9176 if (sr.peek() ==
't' && (sr.peek_at(1) ==
' ' || sr.peek_at(1) ==
'\t')) {
9180 tag.name = sr_parseString(sr);
9182 tag_sizes ts = sr_parseTagTriple(sr);
9184 tag.intValues.resize(
static_cast<size_t>(ts.num_ints));
9186 for (
size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
9187 tag.intValues[i] = sr_parseInt(sr);
9190 tag.floatValues.resize(
static_cast<size_t>(ts.num_reals));
9191 for (
size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
9192 tag.floatValues[i] = sr_parseReal(sr);
9195 tag.stringValues.resize(
static_cast<size_t>(ts.num_strings));
9196 for (
size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
9197 tag.stringValues[i] = sr_parseString(sr);
9200 tags.push_back(tag);
9211bool LoadObjWithCallback(std::istream &inStream,
const callback_t &callback,
9213 MaterialReader *readMatFn ,
9215 std::string *err ) {
9216 StreamReader sr(inStream);
9217 return LoadObjWithCallbackInternal(sr, callback, user_data, readMatFn,
9221bool ObjReader::ParseFromFile(
const std::string &filename,
9222 const ObjReaderConfig &config) {
9223 std::string mtl_search_path;
9225 if (config.mtl_search_path.empty()) {
9230 size_t pos = filename.find_last_of(
"/\\");
9231 if (pos != std::string::npos) {
9232 mtl_search_path = filename.substr(0, pos);
9235 mtl_search_path = config.mtl_search_path;
9238 valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
9239 filename.c_str(), mtl_search_path.c_str(),
9240 config.triangulate, config.vertex_color);
9245bool ObjReader::ParseFromString(
const std::string &obj_text,
9246 const std::string &mtl_text,
9247 const ObjReaderConfig &config) {
9248 std::stringbuf obj_buf(obj_text);
9249 std::stringbuf mtl_buf(mtl_text);
9251 std::istream obj_ifs(&obj_buf);
9252 std::istream mtl_ifs(&mtl_buf);
9254 MaterialStreamReader mtl_ss(mtl_ifs);
9256 valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
9257 &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color);
9263#pragma clang diagnostic pop
bool ParseFromFile(const std::string &filename, const ObjReaderConfig &config=ObjReaderConfig())
const std::string & Warning() const
Definition tiny_obj_loader.h:575
const std::string & Error() const
Definition tiny_obj_loader.h:580
bool ParseFromString(const std::string &obj_text, const std::string &mtl_text, const ObjReaderConfig &config=ObjReaderConfig())
bool Valid() const
Definition tiny_obj_loader.h:564
Definition tiny_obj_loader.h:508
bool vertex_color
Definition tiny_obj_loader.h:520
std::string mtl_search_path
Definition tiny_obj_loader.h:527
Definition tiny_obj_loader.h:390
Definition tiny_obj_loader.h:350
Definition tiny_obj_loader.h:336
Definition tiny_obj_loader.h:372
Definition tiny_obj_loader.h:184
Definition tiny_obj_loader.h:356
Definition tiny_obj_loader.h:378
Definition tiny_obj_loader.h:382
Definition tiny_obj_loader.h:341
Definition tiny_obj_loader.h:328
Definition tiny_obj_loader.h:163