Coverage Report

Created: 2026-04-12 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tinyobjloader/tiny_obj_loader.h
Line
Count
Source
1
/*
2
The MIT License (MIT)
3
4
Copyright (c) 2012-Present, Syoyo Fujita and many contributors.
5
6
Permission is hereby granted, free of charge, to any person obtaining a copy
7
of this software and associated documentation files (the "Software"), to deal
8
in the Software without restriction, including without limitation the rights
9
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
copies of the Software, and to permit persons to whom the Software is
11
furnished to do so, subject to the following conditions:
12
13
The above copyright notice and this permission notice shall be included in
14
all copies or substantial portions of the Software.
15
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
THE SOFTWARE.
23
*/
24
25
//
26
// version 2.0.0 : Add new object oriented API. 1.x API is still provided.
27
//                 * Add python binding.
28
//                 * Support line primitive.
29
//                 * Support points primitive.
30
//                 * Support multiple search path for .mtl(v1 API).
31
//                 * Support vertex skinning weight `vw`(as an tinyobj
32
//                 extension). Note that this differs vertex weight([w]
33
//                 component in `v` line)
34
//                 * Support escaped whitespece in mtllib
35
//                 * Add robust triangulation using Mapbox
36
//                 earcut(TINYOBJLOADER_USE_MAPBOX_EARCUT).
37
// version 1.4.0 : Modifed ParseTextureNameAndOption API
38
// version 1.3.1 : Make ParseTextureNameAndOption API public
39
// version 1.3.0 : Separate warning and error message(breaking API of LoadObj)
40
// version 1.2.3 : Added color space extension('-colorspace') to tex opts.
41
// version 1.2.2 : Parse multiple group names.
42
// version 1.2.1 : Added initial support for line('l') primitive(PR #178)
43
// version 1.2.0 : Hardened implementation(#175)
44
// version 1.1.1 : Support smoothing groups(#162)
45
// version 1.1.0 : Support parsing vertex color(#144)
46
// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138)
47
// version 1.0.7 : Support multiple tex options(#126)
48
// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124)
49
// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43)
50
// version 1.0.4 : Support multiple filenames for 'mtllib'(#112)
51
// version 1.0.3 : Support parsing texture options(#85)
52
// version 1.0.2 : Improve parsing speed by about a factor of 2 for large
53
// files(#105)
54
// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104)
55
// version 1.0.0 : Change data structure. Change license from BSD to MIT.
56
//
57
58
//
59
// Use this in *one* .cc
60
//   #define TINYOBJLOADER_IMPLEMENTATION
61
//   #include "tiny_obj_loader.h"
62
//
63
64
#ifndef TINY_OBJ_LOADER_H_
65
#define TINY_OBJ_LOADER_H_
66
67
#include <map>
68
#include <string>
69
#include <vector>
70
71
namespace tinyobj {
72
73
// C++11 is now the minimum required standard.
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."
76
#endif
77
#define TINYOBJ_OVERRIDE override
78
79
#ifdef __clang__
80
#pragma clang diagnostic push
81
#if __has_warning("-Wzero-as-null-pointer-constant")
82
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
83
#endif
84
85
#pragma clang diagnostic ignored "-Wpadded"
86
87
#endif
88
89
// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ...
90
//
91
//  -blendu on | off                       # set horizontal texture blending
92
//  (default on)
93
//  -blendv on | off                       # set vertical texture blending
94
//  (default on)
95
//  -boost real_value                      # boost mip-map sharpness
96
//  -mm base_value gain_value              # modify texture map values (default
97
//  0 1)
98
//                                         #     base_value = brightness,
99
//                                         gain_value = contrast
100
//  -o u [v [w]]                           # Origin offset             (default
101
//  0 0 0)
102
//  -s u [v [w]]                           # Scale                     (default
103
//  1 1 1)
104
//  -t u [v [w]]                           # Turbulence                (default
105
//  0 0 0)
106
//  -texres resolution                     # texture resolution to create
107
//  -clamp on | off                        # only render texels in the clamped
108
//  0-1 range (default off)
109
//                                         #   When unclamped, textures are
110
//                                         repeated across a surface,
111
//                                         #   when clamped, only texels which
112
//                                         fall within the 0-1
113
//                                         #   range are rendered.
114
//  -bm mult_value                         # bump multiplier (for bump maps
115
//  only)
116
//
117
//  -imfchan r | g | b | m | l | z         # specifies which channel of the file
118
//  is used to
119
//                                         # create a scalar or bump texture.
120
//                                         r:red, g:green,
121
//                                         # b:blue, m:matte, l:luminance,
122
//                                         z:z-depth..
123
//                                         # (the default for bump is 'l' and
124
//                                         for decal is 'm')
125
//  bump -imfchan r bumpmap.tga            # says to use the red channel of
126
//  bumpmap.tga as the bumpmap
127
//
128
// For reflection maps...
129
//
130
//   -type sphere                           # specifies a sphere for a "refl"
131
//   reflection map
132
//   -type cube_top    | cube_bottom |      # when using a cube map, the texture
133
//   file for each
134
//         cube_front  | cube_back   |      # side of the cube is specified
135
//         separately
136
//         cube_left   | cube_right
137
//
138
// TinyObjLoader extension.
139
//
140
//   -colorspace SPACE                      # Color space of the texture. e.g.
141
//   'sRGB` or 'linear'
142
//
143
144
#ifdef TINYOBJLOADER_USE_DOUBLE
145
//#pragma message "using double"
146
typedef double real_t;
147
#else
148
//#pragma message "using float"
149
typedef float real_t;
150
#endif
151
152
typedef enum {
153
  TEXTURE_TYPE_NONE,  // default
154
  TEXTURE_TYPE_SPHERE,
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
161
} texture_type_t;
162
163
struct texture_option_t {
164
  texture_type_t type;      // -type (default TEXTURE_TYPE_NONE)
165
  real_t sharpness;         // -boost (default 1.0?)
166
  real_t brightness;        // base_value in -mm option (default 0)
167
  real_t contrast;          // gain_value in -mm option (default 1)
168
  real_t origin_offset[3];  // -o u [v [w]] (default 0 0 0)
169
  real_t scale[3];          // -s u [v [w]] (default 1 1 1)
170
  real_t turbulence[3];     // -t u [v [w]] (default 0 0 0)
171
  int texture_resolution;   // -texres resolution (No default value in the spec.
172
                            // We'll use -1)
173
  bool clamp;               // -clamp (default false)
174
  char imfchan;  // -imfchan (the default for bump is 'l' and for decal is 'm')
175
  bool blendu;   // -blendu (default on)
176
  bool blendv;   // -blendv (default on)
177
  real_t bump_multiplier;  // -bm (for bump maps only, default 1.0)
178
179
  // extension
180
  std::string colorspace;  // Explicitly specify color space of stored texel
181
                           // value. Usually `sRGB` or `linear` (default empty).
182
};
183
184
struct material_t {
185
  std::string name;
186
187
  real_t ambient[3];
188
  real_t diffuse[3];
189
  real_t specular[3];
190
  real_t transmittance[3];
191
  real_t emission[3];
192
  real_t shininess;
193
  real_t ior;       // index of refraction
194
  real_t dissolve;  // 1 == opaque; 0 == fully transparent
195
  // illumination model (see http://www.fileformat.info/format/material/)
196
  int illum;
197
198
  int dummy;  // Suppress padding warning.
199
200
  std::string ambient_texname;   // map_Ka. For ambient or ambient occlusion.
201
  std::string diffuse_texname;   // map_Kd
202
  std::string specular_texname;  // map_Ks
203
  std::string specular_highlight_texname;  // map_Ns
204
  std::string bump_texname;                // map_bump, map_Bump, bump
205
  std::string displacement_texname;        // disp
206
  std::string alpha_texname;               // map_d
207
  std::string reflection_texname;          // refl
208
209
  texture_option_t ambient_texopt;
210
  texture_option_t diffuse_texopt;
211
  texture_option_t specular_texopt;
212
  texture_option_t specular_highlight_texopt;
213
  texture_option_t bump_texopt;
214
  texture_option_t displacement_texopt;
215
  texture_option_t alpha_texopt;
216
  texture_option_t reflection_texopt;
217
218
  // PBR extension
219
  // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
220
  real_t roughness;            // [0, 1] default 0
221
  real_t metallic;             // [0, 1] default 0
222
  real_t sheen;                // [0, 1] default 0
223
  real_t clearcoat_thickness;  // [0, 1] default 0
224
  real_t clearcoat_roughness;  // [0, 1] default 0
225
  real_t anisotropy;           // aniso. [0, 1] default 0
226
  real_t anisotropy_rotation;  // anisor. [0, 1] default 0
227
  real_t pad0;
228
  std::string roughness_texname;  // map_Pr
229
  std::string metallic_texname;   // map_Pm
230
  std::string sheen_texname;      // map_Ps
231
  std::string emissive_texname;   // map_Ke
232
  std::string normal_texname;     // norm. For normal mapping.
233
234
  texture_option_t roughness_texopt;
235
  texture_option_t metallic_texopt;
236
  texture_option_t sheen_texopt;
237
  texture_option_t emissive_texopt;
238
  texture_option_t normal_texopt;
239
240
  int pad2;
241
242
  std::map<std::string, std::string> unknown_parameter;
243
244
#ifdef TINY_OBJ_LOADER_PYTHON_BINDING
245
  // For pybind11
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]);
251
252
    return values;
253
  }
254
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]);
260
261
    return values;
262
  }
263
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]);
269
270
    return values;
271
  }
272
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]);
278
279
    return values;
280
  }
281
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]);
287
288
    return values;
289
  }
290
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]);
295
  }
296
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]);
301
  }
302
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]);
307
  }
308
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]);
313
  }
314
315
  std::string GetCustomParameter(const std::string &key) {
316
    std::map<std::string, std::string>::const_iterator it =
317
        unknown_parameter.find(key);
318
319
    if (it != unknown_parameter.end()) {
320
      return it->second;
321
    }
322
    return std::string();
323
  }
324
325
#endif
326
};
327
328
struct tag_t {
329
  std::string name;
330
331
  std::vector<int> intValues;
332
  std::vector<real_t> floatValues;
333
  std::vector<std::string> stringValues;
334
};
335
336
struct joint_and_weight_t {
337
  int joint_id;
338
  real_t weight;
339
};
340
341
struct skin_weight_t {
342
  int vertex_id;  // Corresponding vertex index in `attrib_t::vertices`.
343
                  // Compared to `index_t`, this index must be positive and
344
                  // start with 0(does not allow relative indexing)
345
  std::vector<joint_and_weight_t> weightValues;
346
};
347
348
// Index struct to support different indices for vtx/normal/texcoord.
349
// -1 means not used.
350
struct index_t {
351
  int vertex_index;
352
  int normal_index;
353
  int texcoord_index;
354
};
355
356
struct mesh_t {
357
  std::vector<index_t> indices;
358
  std::vector<unsigned int>
359
      num_face_vertices;          // The number of vertices per
360
                                  // face. 3 = triangle, 4 = quad, ...
361
  std::vector<int> material_ids;  // per-face material ID
362
  std::vector<unsigned int> smoothing_group_ids;  // per-face smoothing group
363
                                                  // ID(0 = off. positive value
364
                                                  // = group id)
365
  std::vector<tag_t> tags;                        // SubD tag
366
};
367
368
// struct path_t {
369
//  std::vector<int> indices;  // pairs of indices for lines
370
//};
371
372
struct lines_t {
373
  // Linear flattened indices.
374
  std::vector<index_t> indices;        // indices for vertices(poly lines)
375
  std::vector<int> num_line_vertices;  // The number of vertices per line.
376
};
377
378
struct points_t {
379
  std::vector<index_t> indices;  // indices for points
380
};
381
382
struct shape_t {
383
  std::string name;
384
  mesh_t mesh;
385
  lines_t lines;
386
  points_t points;
387
};
388
389
// Vertex attributes
390
struct attrib_t {
391
  std::vector<real_t> vertices;  // 'v'(xyz)
392
393
  // For backward compatibility, we store vertex weight in separate array.
394
  std::vector<real_t> vertex_weights;  // 'v'(w)
395
  std::vector<real_t> normals;         // 'vn'
396
  std::vector<real_t> texcoords;       // 'vt'(uv)
397
398
  // For backward compatibility, we store texture coordinate 'w' in separate
399
  // array.
400
  std::vector<real_t> texcoord_ws;  // 'vt'(w)
401
  std::vector<real_t> colors;       // extension: vertex colors
402
403
  //
404
  // TinyObj extension.
405
  //
406
407
  // NOTE(syoyo): array index is based on the appearance order.
408
  // To get a corresponding skin weight for a specific vertex id `vid`,
409
  // Need to reconstruct a look up table: `skin_weight_t::vertex_id` == `vid`
410
  // (e.g. using std::map, std::unordered_map)
411
  std::vector<skin_weight_t> skin_weights;
412
413
8.56k
  attrib_t() {}
414
415
  //
416
  // For pybind11
417
  //
418
0
  const std::vector<real_t> &GetVertices() const { return vertices; }
419
420
0
  const std::vector<real_t> &GetVertexWeights() const { return vertex_weights; }
421
};
422
423
struct callback_t {
424
  // W is optional and set to 1 if there is no `w` item in `v` line
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);
429
430
  // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in
431
  // `vt` line.
432
  void (*texcoord_cb)(void *user_data, real_t x, real_t y, real_t z);
433
434
  // called per 'f' line. num_indices is the number of face indices(e.g. 3 for
435
  // triangle, 4 for quad)
436
  // 0 will be passed for undefined index in index_t members.
437
  void (*index_cb)(void *user_data, index_t *indices, int num_indices);
438
  // `name` material name, `material_id` = the array index of material_t[]. -1
439
  // if
440
  // a material not found in .mtl
441
  void (*usemtl_cb)(void *user_data, const char *name, int material_id);
442
  // `materials` = parsed material data.
443
  void (*mtllib_cb)(void *user_data, const material_t *materials,
444
                    int num_materials);
445
  // There may be multiple group names
446
  void (*group_cb)(void *user_data, const char **names, int num_names);
447
  void (*object_cb)(void *user_data, const char *name);
448
449
  callback_t()
450
      : vertex_cb(NULL),
451
        vertex_color_cb(NULL),
452
        normal_cb(NULL),
453
        texcoord_cb(NULL),
454
        index_cb(NULL),
455
        usemtl_cb(NULL),
456
        mtllib_cb(NULL),
457
        group_cb(NULL),
458
0
        object_cb(NULL) {}
459
};
460
461
class MaterialReader {
462
 public:
463
8.54k
  MaterialReader() {}
464
  virtual ~MaterialReader();
465
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;
470
};
471
472
///
473
/// Read .mtl from a file.
474
///
475
class MaterialFileReader : public MaterialReader {
476
 public:
477
  // Path could contain separator(';' in Windows, ':' in Posix)
478
  explicit MaterialFileReader(const std::string &mtl_basedir)
479
0
      : m_mtlBaseDir(mtl_basedir) {}
480
0
  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;
485
486
 private:
487
  std::string m_mtlBaseDir;
488
};
489
490
///
491
/// Read .mtl from a stream.
492
///
493
class MaterialStreamReader : public MaterialReader {
494
 public:
495
  explicit MaterialStreamReader(std::istream &inStream)
496
8.54k
      : m_inStream(inStream) {}
497
0
  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;
502
503
 private:
504
  std::istream &m_inStream;
505
};
506
507
// v2 API
508
struct ObjReaderConfig {
509
  bool triangulate;  // triangulate polygon?
510
511
  // Currently not used.
512
  // "simple" or empty: Create triangle fan
513
  // "earcut": Use the algorithm based on Ear clipping
514
  std::string triangulation_method;
515
516
  /// Parse vertex color.
517
  /// If vertex color is not present, its filled with default value.
518
  /// false = no vertex color
519
  /// This will increase memory of parsed .obj
520
  bool vertex_color;
521
522
  ///
523
  /// Search path to .mtl file.
524
  /// Default = "" = search from the same directory of .obj file.
525
  /// Valid only when loading .obj from a file.
526
  ///
527
  std::string mtl_search_path;
528
529
  ObjReaderConfig()
530
8.56k
      : triangulate(true), triangulation_method("simple"), vertex_color(true) {}
531
};
532
533
///
534
/// Wavefront .obj reader class(v2 API)
535
///
536
class ObjReader {
537
 public:
538
8.56k
  ObjReader() : valid_(false) {}
539
540
  ///
541
  /// Load .obj and .mtl from a file.
542
  ///
543
  /// @param[in] filename wavefront .obj filename
544
  /// @param[in] config Reader configuration
545
  ///
546
  bool ParseFromFile(const std::string &filename,
547
                     const ObjReaderConfig &config = ObjReaderConfig());
548
549
  ///
550
  /// Parse .obj from a text string.
551
  /// Need to supply .mtl text string by `mtl_text`.
552
  /// This function ignores `mtllib` line in .obj text.
553
  ///
554
  /// @param[in] obj_text wavefront .obj filename
555
  /// @param[in] mtl_text wavefront .mtl filename
556
  /// @param[in] config Reader configuration
557
  ///
558
  bool ParseFromString(const std::string &obj_text, const std::string &mtl_text,
559
                       const ObjReaderConfig &config = ObjReaderConfig());
560
561
  ///
562
  /// .obj was loaded or parsed correctly.
563
  ///
564
0
  bool Valid() const { return valid_; }
565
566
0
  const attrib_t &GetAttrib() const { return attrib_; }
567
568
0
  const std::vector<shape_t> &GetShapes() const { return shapes_; }
569
570
0
  const std::vector<material_t> &GetMaterials() const { return materials_; }
571
572
  ///
573
  /// Warning message(may be filled after `Load` or `Parse`)
574
  ///
575
0
  const std::string &Warning() const { return warning_; }
576
577
  ///
578
  /// Error message(filled when `Load` or `Parse` failed)
579
  ///
580
0
  const std::string &Error() const { return error_; }
581
582
 private:
583
  bool valid_;
584
585
  attrib_t attrib_;
586
  std::vector<shape_t> shapes_;
587
  std::vector<material_t> materials_;
588
589
  std::string warning_;
590
  std::string error_;
591
};
592
593
/// ==>>========= Legacy v1 API =============================================
594
595
/// Loads .obj from a file.
596
/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data
597
/// 'shapes' will be filled with parsed shape data
598
/// Returns true when loading .obj become success.
599
/// Returns warning message into `warn`, and error message into `err`
600
/// 'mtl_basedir' is optional, and used for base directory for .mtl file.
601
/// In default(`NULL'), .mtl file is searched from an application's working
602
/// directory.
603
/// 'triangulate' is optional, and used whether triangulate polygon face in .obj
604
/// or not.
605
/// Option 'default_vcols_fallback' specifies whether vertex colors should
606
/// always be defined, even if no colors are given (fallback to white).
607
bool 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);
612
613
/// Loads .obj from a file with custom user callback.
614
/// .mtl is loaded as usual and parsed material_t data will be passed to
615
/// `callback.mtllib_cb`.
616
/// Returns true when loading .obj/.mtl become success.
617
/// Returns warning message into `warn`, and error message into `err`
618
/// See `examples/callback_api/` for how to use this function.
619
bool 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);
623
624
/// Loads object from a std::istream, uses `readMatFn` to retrieve
625
/// std::istream for materials.
626
/// Returns true when loading .obj become success.
627
/// Returns warning and error message into `err`
628
bool 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);
633
634
/// Loads materials into std::map
635
void LoadMtl(std::map<std::string, int> *material_map,
636
             std::vector<material_t> *materials, std::istream *inStream,
637
             std::string *warning, std::string *err);
638
639
///
640
/// Parse texture name and texture option for custom texture parameter through
641
/// material::unknown_parameter
642
///
643
/// @param[out] texname Parsed texture name
644
/// @param[out] texopt Parsed texopt
645
/// @param[in] linebuf Input string
646
///
647
bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt,
648
                               const char *linebuf);
649
650
/// =<<========== Legacy v1 API =============================================
651
652
}  // namespace tinyobj
653
654
#endif  // TINY_OBJ_LOADER_H_
655
656
#ifdef TINYOBJLOADER_IMPLEMENTATION
657
#include <cassert>
658
#include <cctype>
659
#include <climits>
660
#include <cmath>
661
#include <cstddef>
662
#include <cstdint>
663
#include <cerrno>
664
#include <cstdlib>
665
#include <cstring>
666
#include <fstream>
667
#include <limits>
668
669
#ifdef _WIN32
670
#ifndef WIN32_LEAN_AND_MEAN
671
#define WIN32_LEAN_AND_MEAN
672
#endif
673
#ifndef NOMINMAX
674
#define NOMINMAX
675
#endif
676
#include <windows.h>
677
#endif
678
679
#ifdef TINYOBJLOADER_USE_MMAP
680
#if !defined(_WIN32)
681
// POSIX headers for mmap
682
#include <fcntl.h>
683
#include <sys/mman.h>
684
#include <sys/stat.h>
685
#include <unistd.h>
686
#endif
687
#endif  // TINYOBJLOADER_USE_MMAP
688
#include <set>
689
#include <sstream>
690
#include <utility>
691
692
#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
693
694
#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT
695
// Assume earcut.hpp is included outside of tiny_obj_loader.h
696
#else
697
698
#ifdef __clang__
699
#pragma clang diagnostic push
700
#pragma clang diagnostic ignored "-Weverything"
701
#endif
702
703
#include <array>
704
705
#include "mapbox/earcut.hpp"
706
707
#ifdef __clang__
708
#pragma clang diagnostic pop
709
#endif
710
711
#endif
712
713
#endif  // TINYOBJLOADER_USE_MAPBOX_EARCUT
714
715
#ifdef _WIN32
716
// Converts a UTF-8 encoded string to a UTF-16 wide string for use with
717
// Windows file APIs that support Unicode paths (including paths longer than
718
// MAX_PATH when combined with the extended-length path prefix).
719
static std::wstring UTF8ToWchar(const std::string &str) {
720
  if (str.empty()) return std::wstring();
721
  int size_needed =
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');
726
  int result =
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();
730
  return wstr;
731
}
732
733
// Prepends the Windows extended-length path prefix ("\\?\") to an absolute
734
// path when the path length meets or exceeds MAX_PATH (260 characters).
735
// This allows Windows APIs to handle paths up to 32767 characters long.
736
// UNC paths (starting with "\\") are converted to "\\?\UNC\" form.
737
static 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\\";
741
742
  // Already has the extended-length prefix; return as-is.
743
  if (wpath.size() >= kLongPathPrefix.size() &&
744
      wpath.substr(0, kLongPathPrefix.size()) == kLongPathPrefix) {
745
    return wpath;
746
  }
747
748
  // Only add the prefix when the path is long enough to require it.
749
  if (wpath.size() < MAX_PATH) {
750
    return wpath;
751
  }
752
753
  // Normalize forward slashes to backslashes: the extended-length "\\?\"
754
  // prefix requires backslash separators only.
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'\\';
758
  }
759
760
  // UNC path: "\\server\share\..." -> "\\?\UNC\server\share\..."
761
  if (normalized.size() >= kUNCPrefix.size() &&
762
      normalized.substr(0, kUNCPrefix.size()) == kUNCPrefix) {
763
    return kLongUNCPathPrefix + normalized.substr(kUNCPrefix.size());
764
  }
765
766
  // Absolute path with drive letter: "C:\..." -> "\\?\C:\..."
767
  if (normalized.size() >= 2 && normalized[1] == L':') {
768
    return kLongPathPrefix + normalized;
769
  }
770
771
  return normalized;
772
}
773
#endif  // _WIN32
774
775
// --------------------------------------------------------------------------
776
// Embedded fast_float v8.0.2 for high-performance, bit-exact float parsing.
777
// Disable by defining TINYOBJLOADER_DISABLE_FAST_FLOAT before including
778
// this file with TINYOBJLOADER_IMPLEMENTATION.
779
// --------------------------------------------------------------------------
780
#ifndef TINYOBJLOADER_DISABLE_FAST_FLOAT
781
782
// Standard headers needed by the embedded fast_float.
783
#include <cfloat>
784
#include <cstdint>
785
786
namespace tinyobj_ff {
787
788
// --- integral_constant, true_type, false_type ---
789
template <typename T, T V>
790
struct 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; }
795
};
796
typedef integral_constant<bool, true>  true_type;
797
typedef integral_constant<bool, false> false_type;
798
799
// --- is_same ---
800
template <typename T, typename U> struct is_same       : false_type {};
801
template <typename T>             struct is_same<T, T> : true_type  {};
802
803
// --- enable_if ---
804
template <bool B, typename T = void> struct enable_if {};
805
template <typename T>                struct enable_if<true, T> { typedef T type; };
806
807
// --- conditional ---
808
template <bool B, typename T, typename F> struct conditional              { typedef T type; };
809
template <typename T, typename F>         struct conditional<false, T, F> { typedef F type; };
810
811
// --- is_integral ---
812
template <typename T> struct is_integral : false_type {};
813
template <> struct is_integral<bool>               : true_type {};
814
template <> struct is_integral<char>               : true_type {};
815
template <> struct is_integral<signed char>        : true_type {};
816
template <> struct is_integral<unsigned char>      : true_type {};
817
template <> struct is_integral<short>              : true_type {};
818
template <> struct is_integral<unsigned short>     : true_type {};
819
template <> struct is_integral<int>                : true_type {};
820
template <> struct is_integral<unsigned int>       : true_type {};
821
template <> struct is_integral<long>               : true_type {};
822
template <> struct is_integral<unsigned long>      : true_type {};
823
template <> struct is_integral<long long>          : true_type {};
824
template <> struct is_integral<unsigned long long> : true_type {};
825
template <> struct is_integral<wchar_t>            : true_type {};
826
template <> struct is_integral<char16_t>           : true_type {};
827
template <> struct is_integral<char32_t>           : true_type {};
828
829
// --- is_signed ---
830
template <typename T> struct is_signed : integral_constant<bool, T(-1) < T(0)> {};
831
832
// --- underlying_type (uses compiler builtin) ---
833
template <typename T> struct underlying_type {
834
  typedef __underlying_type(T) type;
835
};
836
837
// --- ff_errc (replaces std::errc, our own enum - no system_error needed) ---
838
enum class ff_errc { ok = 0, invalid_argument = 22, result_out_of_range = 34 };
839
840
// --- min_val (replaces std::min, avoids Windows min/max macro conflicts) ---
841
template <typename T>
842
0
inline T min_val(T a, T b) { return (b < a) ? b : a; }
843
844
// --- copy_n ---
845
template <typename InputIt, typename Size, typename OutputIt>
846
0
inline OutputIt copy_n(InputIt first, Size count, OutputIt result) {
847
0
  for (Size i = 0; i < count; ++i) *result++ = *first++;
848
0
  return result;
849
0
}
850
851
// --- copy_backward ---
852
template <typename BidirIt1, typename BidirIt2>
853
0
inline BidirIt2 copy_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last) {
854
0
  while (first != last) *(--d_last) = *(--last);
855
0
  return d_last;
856
0
}
857
858
// --- fill ---
859
template <typename ForwardIt, typename T>
860
0
inline void fill(ForwardIt first, ForwardIt last, const T &value) {
861
0
  for (; first != last; ++first) *first = value;
862
0
}
Unexecuted instantiation: void tinyobj_ff::fill<unsigned long*, unsigned long>(unsigned long*, unsigned long*, unsigned long const&)
Unexecuted instantiation: void tinyobj_ff::fill<unsigned long*, int>(unsigned long*, unsigned long*, int const&)
863
864
// --- distance ---
865
template <typename It>
866
inline typename conditional<true, long long, It>::type
867
602
distance(It first, It last) {
868
602
  return last - first;
869
602
}
870
871
}  // namespace tinyobj_ff
872
873
// --- Begin embedded fast_float v8.0.2 (MIT / Apache-2.0 / BSL-1.0) ---
874
// https://github.com/fastfloat/fast_float
875
// fast_float by Daniel Lemire
876
// fast_float by João Paulo Magalhaes
877
//
878
//
879
// with contributions from Eugene Golushkov
880
// with contributions from Maksim Kita
881
// with contributions from Marcin Wojdyr
882
// with contributions from Neal Richardson
883
// with contributions from Tim Paine
884
// with contributions from Fabio Pellacini
885
// with contributions from Lénárd Szolnoki
886
// with contributions from Jan Pharago
887
// with contributions from Maya Warrier
888
// with contributions from Taha Khokhar
889
// with contributions from Anders Dalvander
890
//
891
//
892
// Licensed under the Apache License, Version 2.0, or the
893
// MIT License or the Boost License. This file may not be copied,
894
// modified, or distributed except according to those terms.
895
//
896
// MIT License Notice
897
//
898
//    MIT License
899
//
900
//    Copyright (c) 2021 The fast_float authors
901
//
902
//    Permission is hereby granted, free of charge, to any
903
//    person obtaining a copy of this software and associated
904
//    documentation files (the "Software"), to deal in the
905
//    Software without restriction, including without
906
//    limitation the rights to use, copy, modify, merge,
907
//    publish, distribute, sublicense, and/or sell copies of
908
//    the Software, and to permit persons to whom the Software
909
//    is furnished to do so, subject to the following
910
//    conditions:
911
//
912
//    The above copyright notice and this permission notice
913
//    shall be included in all copies or substantial portions
914
//    of the Software.
915
//
916
//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
917
//    ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
918
//    TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
919
//    PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
920
//    SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
921
//    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
922
//    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
923
//    IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
924
//    DEALINGS IN THE SOFTWARE.
925
//
926
// Apache License (Version 2.0) Notice
927
//
928
//    Copyright 2021 The fast_float authors
929
//    Licensed under the Apache License, Version 2.0 (the "License");
930
//    you may not use this file except in compliance with the License.
931
//    You may obtain a copy of the License at
932
//
933
//    http://www.apache.org/licenses/LICENSE-2.0
934
//
935
//    Unless required by applicable law or agreed to in writing, software
936
//    distributed under the License is distributed on an "AS IS" BASIS,
937
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
938
//    See the License for the specific language governing permissions and
939
//
940
// BOOST License Notice
941
//
942
//    Boost Software License - Version 1.0 - August 17th, 2003
943
//
944
//    Permission is hereby granted, free of charge, to any person or organization
945
//    obtaining a copy of the software and accompanying documentation covered by
946
//    this license (the "Software") to use, reproduce, display, distribute,
947
//    execute, and transmit the Software, and to prepare derivative works of the
948
//    Software, and to permit third-parties to whom the Software is furnished to
949
//    do so, all subject to the following:
950
//
951
//    The copyright notices in the Software and this entire statement, including
952
//    the above license grant, this restriction and the following disclaimer,
953
//    must be included in all copies of the Software, in whole or in part, and
954
//    all derivative works of the Software, unless such copies or derivative
955
//    works are solely in the form of machine-executable object code generated by
956
//    a source language processor.
957
//
958
//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
959
//    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
960
//    FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
961
//    SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
962
//    FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
963
//    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
964
//    DEALINGS IN THE SOFTWARE.
965
//
966
967
#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
968
#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
969
970
#ifdef __has_include
971
#if __has_include(<version>)
972
#include <version>
973
#endif
974
#endif
975
976
// Testing for https://wg21.link/N3652, adopted in C++14
977
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
978
#define FASTFLOAT_CONSTEXPR14 constexpr
979
#else
980
#define FASTFLOAT_CONSTEXPR14
981
#endif
982
983
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
984
#define FASTFLOAT_HAS_BIT_CAST 1
985
#else
986
#define FASTFLOAT_HAS_BIT_CAST 0
987
#endif
988
989
#if defined(__cpp_lib_is_constant_evaluated) &&                                \
990
    __cpp_lib_is_constant_evaluated >= 201811L
991
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
992
#else
993
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
994
#endif
995
996
#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
997
#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x)
998
#else
999
9.50k
#define FASTFLOAT_IF_CONSTEXPR17(x) if (x)
1000
#endif
1001
1002
// Testing for relevant C++20 constexpr library features
1003
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST &&           \
1004
    defined(__cpp_lib_constexpr_algorithms) &&                                 \
1005
    __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
1006
#define FASTFLOAT_CONSTEXPR20 constexpr
1007
#define FASTFLOAT_IS_CONSTEXPR 1
1008
#else
1009
#define FASTFLOAT_CONSTEXPR20
1010
#define FASTFLOAT_IS_CONSTEXPR 0
1011
#endif
1012
1013
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
1014
#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0
1015
#else
1016
#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1
1017
#endif
1018
1019
#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
1020
1021
#ifndef FASTFLOAT_FLOAT_COMMON_H
1022
#define FASTFLOAT_FLOAT_COMMON_H
1023
1024
#include <cassert>
1025
#include <cstring>
1026
#include <limits>
1027
#ifdef __has_include
1028
#if __has_include(<stdfloat>) && (__cplusplus > 202002L || (defined(_MSVC_LANG) && (_MSVC_LANG > 202002L)))
1029
#include <stdfloat>
1030
#endif
1031
#endif
1032
1033
#define FASTFLOAT_VERSION_MAJOR 8
1034
#define FASTFLOAT_VERSION_MINOR 0
1035
#define FASTFLOAT_VERSION_PATCH 2
1036
1037
#define FASTFLOAT_STRINGIZE_IMPL(x) #x
1038
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
1039
1040
#define FASTFLOAT_VERSION_STR                                                  \
1041
  FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MAJOR)                                 \
1042
  "." FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MINOR) "." FASTFLOAT_STRINGIZE(    \
1043
      FASTFLOAT_VERSION_PATCH)
1044
1045
#define FASTFLOAT_VERSION                                                      \
1046
  (FASTFLOAT_VERSION_MAJOR * 10000 + FASTFLOAT_VERSION_MINOR * 100 +           \
1047
   FASTFLOAT_VERSION_PATCH)
1048
1049
namespace fast_float {
1050
1051
enum class chars_format : uint64_t;
1052
1053
namespace detail {
1054
constexpr chars_format basic_json_fmt = chars_format(1 << 5);
1055
constexpr chars_format basic_fortran_fmt = chars_format(1 << 6);
1056
} // namespace detail
1057
1058
enum class chars_format : uint64_t {
1059
  scientific = 1 << 0,
1060
  fixed = 1 << 2,
1061
  hex = 1 << 3,
1062
  no_infnan = 1 << 4,
1063
  // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6
1064
  json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan,
1065
  // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed.
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,
1071
};
1072
1073
template <typename UC> struct from_chars_result_t {
1074
  UC const *ptr;
1075
  tinyobj_ff::ff_errc ec;
1076
};
1077
1078
using from_chars_result = from_chars_result_t<char>;
1079
1080
template <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
5.14k
      : format(fmt), decimal_point(dot), base(b) {}
1084
1085
  /** Which number formats are accepted */
1086
  chars_format format;
1087
  /** The character used as decimal point */
1088
  UC decimal_point;
1089
  /** The base used for integers */
1090
  int base;
1091
};
1092
1093
using parse_options = parse_options_t<char>;
1094
1095
} // namespace fast_float
1096
1097
#if FASTFLOAT_HAS_BIT_CAST
1098
#include <bit>
1099
#endif
1100
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
1112
#else
1113
  // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
1114
// We can never tell the register width, but the SIZE_MAX is a good
1115
// approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max
1116
// portability.
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
1123
#else
1124
#error Unknown platform (not 32-bit, not 64-bit?)
1125
#endif
1126
#endif
1127
1128
#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) ||           \
1129
    (defined(_M_ARM64) && !defined(__MINGW32__))
1130
#include <intrin.h>
1131
#endif
1132
1133
#if defined(_MSC_VER) && !defined(__clang__)
1134
#define FASTFLOAT_VISUAL_STUDIO 1
1135
#endif
1136
1137
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
1138
#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
1139
#elif defined _WIN32
1140
#define FASTFLOAT_IS_BIG_ENDIAN 0
1141
#else
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>
1148
#else
1149
#ifdef __has_include
1150
#if __has_include(<endian.h>)
1151
#include <endian.h>
1152
#endif //__has_include(<endian.h>)
1153
#endif //__has_include
1154
#endif
1155
#
1156
#ifndef __BYTE_ORDER__
1157
// safe choice
1158
#define FASTFLOAT_IS_BIG_ENDIAN 0
1159
#endif
1160
#
1161
#ifndef __ORDER_LITTLE_ENDIAN__
1162
// safe choice
1163
#define FASTFLOAT_IS_BIG_ENDIAN 0
1164
#endif
1165
#
1166
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1167
#define FASTFLOAT_IS_BIG_ENDIAN 0
1168
#else
1169
#define FASTFLOAT_IS_BIG_ENDIAN 1
1170
#endif
1171
#endif
1172
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
1177
#endif
1178
1179
#if defined(__aarch64__) || defined(_M_ARM64)
1180
#define FASTFLOAT_NEON 1
1181
#endif
1182
1183
#if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON)
1184
#define FASTFLOAT_HAS_SIMD 1
1185
#endif
1186
1187
#if defined(__GNUC__)
1188
// disable -Wcast-align=strict (GCC only)
1189
#define FASTFLOAT_SIMD_DISABLE_WARNINGS                                        \
1190
  _Pragma("GCC diagnostic push")                                               \
1191
      _Pragma("GCC diagnostic ignored \"-Wcast-align\"")
1192
#else
1193
#define FASTFLOAT_SIMD_DISABLE_WARNINGS
1194
#endif
1195
1196
#if defined(__GNUC__)
1197
#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
1198
#else
1199
#define FASTFLOAT_SIMD_RESTORE_WARNINGS
1200
#endif
1201
1202
#ifdef FASTFLOAT_VISUAL_STUDIO
1203
#define fastfloat_really_inline __forceinline
1204
#else
1205
#define fastfloat_really_inline inline __attribute__((always_inline))
1206
#endif
1207
1208
#ifndef FASTFLOAT_ASSERT
1209
#define FASTFLOAT_ASSERT(x)                                                    \
1210
0
  { ((void)(x)); }
1211
#endif
1212
1213
#ifndef FASTFLOAT_DEBUG_ASSERT
1214
#define FASTFLOAT_DEBUG_ASSERT(x)                                              \
1215
0
  { ((void)(x)); }
1216
#endif
1217
1218
// rust style `try!()` macro, or `?` operator
1219
#define FASTFLOAT_TRY(x)                                                       \
1220
0
  {                                                                            \
1221
0
    if (!(x))                                                                  \
1222
0
      return false;                                                            \
1223
0
  }
1224
1225
#define FASTFLOAT_ENABLE_IF(...)                                               \
1226
  typename tinyobj_ff::enable_if<(__VA_ARGS__), int>::type
1227
1228
namespace fast_float {
1229
1230
0
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
1231
0
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
1232
0
  return std::is_constant_evaluated();
1233
0
#else
1234
0
  return false;
1235
0
#endif
1236
0
}
1237
1238
template <typename T>
1239
struct 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
1244
#endif
1245
#ifdef __STDCPP_FLOAT32_T__
1246
                    || tinyobj_ff::is_same<T, std::float32_t>::value
1247
#endif
1248
#ifdef __STDCPP_FLOAT16_T__
1249
                    || tinyobj_ff::is_same<T, std::float16_t>::value
1250
#endif
1251
#ifdef __STDCPP_BFLOAT16_T__
1252
                    || tinyobj_ff::is_same<T, std::bfloat16_t>::value
1253
#endif
1254
          > {
1255
};
1256
1257
template <typename T>
1258
using 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;
1264
1265
template <typename T> struct is_supported_integer_type : tinyobj_ff::is_integral<T> {};
1266
1267
template <typename UC>
1268
struct 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
1273
#ifdef __cpp_char8_t
1274
                                       || tinyobj_ff::is_same<UC, char8_t>::value
1275
#endif
1276
                             > {
1277
};
1278
1279
// Compares two ASCII strings in a case insensitive manner.
1280
template <typename UC>
1281
inline FASTFLOAT_CONSTEXPR14 bool
1282
fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
1283
622
                      size_t length) {
1284
653
  for (size_t i = 0; i < length; ++i) {
1285
653
    UC const actual = actual_mixedcase[i];
1286
653
    if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
1287
622
      return false;
1288
622
    }
1289
653
  }
1290
0
  return true;
1291
622
}
1292
1293
#ifndef FLT_EVAL_METHOD
1294
#error "FLT_EVAL_METHOD should be defined, please include cfloat."
1295
#endif
1296
1297
// a pointer and a length to a contiguous block of memory
1298
template <typename T> struct span {
1299
  T const *ptr;
1300
  size_t length;
1301
1302
5.10k
  constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {}
fast_float::span<char const>::span(char const*, unsigned long)
Line
Count
Source
1302
5.10k
  constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {}
Unexecuted instantiation: fast_float::span<unsigned long>::span(unsigned long const*, unsigned long)
1303
1304
14.8k
  constexpr span() : ptr(nullptr), length(0) {}
1305
1306
15
  constexpr size_t len() const noexcept { return length; }
fast_float::span<char const>::len() const
Line
Count
Source
1306
15
  constexpr size_t len() const noexcept { return length; }
Unexecuted instantiation: fast_float::span<unsigned long>::len() const
1307
1308
0
  FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept {
1309
0
    FASTFLOAT_DEBUG_ASSERT(index < length);
1310
0
    return ptr[index];
1311
0
  }
1312
};
1313
1314
struct value128 {
1315
  uint64_t low;
1316
  uint64_t high;
1317
1318
0
  constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
1319
1320
26
  constexpr value128() : low(0), high(0) {}
1321
};
1322
1323
/* Helper C++14 constexpr generic implementation of leading_zeroes */
1324
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int
1325
0
leading_zeroes_generic(uint64_t input_num, int last_bit = 0) {
1326
0
  if (input_num & uint64_t(0xffffffff00000000)) {
1327
0
    input_num >>= 32;
1328
0
    last_bit |= 32;
1329
0
  }
1330
0
  if (input_num & uint64_t(0xffff0000)) {
1331
0
    input_num >>= 16;
1332
0
    last_bit |= 16;
1333
0
  }
1334
0
  if (input_num & uint64_t(0xff00)) {
1335
0
    input_num >>= 8;
1336
0
    last_bit |= 8;
1337
0
  }
1338
0
  if (input_num & uint64_t(0xf0)) {
1339
0
    input_num >>= 4;
1340
0
    last_bit |= 4;
1341
0
  }
1342
0
  if (input_num & uint64_t(0xc)) {
1343
0
    input_num >>= 2;
1344
0
    last_bit |= 2;
1345
0
  }
1346
0
  if (input_num & uint64_t(0x2)) { /* input_num >>=  1; */
1347
0
    last_bit |= 1;
1348
0
  }
1349
0
  return 63 - last_bit;
1350
0
}
1351
1352
/* result might be undefined when input_num is zero */
1353
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int
1354
25
leading_zeroes(uint64_t input_num) {
1355
25
  assert(input_num > 0);
1356
25
  if (cpp20_and_in_constexpr()) {
1357
0
    return leading_zeroes_generic(input_num);
1358
0
  }
1359
#ifdef FASTFLOAT_VISUAL_STUDIO
1360
#if defined(_M_X64) || defined(_M_ARM64)
1361
  unsigned long leading_zero = 0;
1362
  // Search the mask data from most significant bit (MSB)
1363
  // to least significant bit (LSB) for a set bit (1).
1364
  _BitScanReverse64(&leading_zero, input_num);
1365
  return (int)(63 - leading_zero);
1366
#else
1367
  return leading_zeroes_generic(input_num);
1368
#endif
1369
#else
1370
25
  return __builtin_clzll(input_num);
1371
25
#endif
1372
25
}
1373
1374
// slow emulation routine for 32-bit
1375
0
fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) {
1376
0
  return x * (uint64_t)y;
1377
0
}
1378
1379
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
1380
0
umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
1381
0
  uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
1382
0
  uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
1383
0
  uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
1384
0
  uint64_t adbc_carry = (uint64_t)(adbc < ad);
1385
0
  uint64_t lo = bd + (adbc << 32);
1386
0
  *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
1387
0
        (adbc_carry << 32) + (uint64_t)(lo < bd);
1388
0
  return lo;
1389
0
}
1390
1391
#ifdef FASTFLOAT_32BIT
1392
1393
// slow emulation routine for 32-bit
1394
#if !defined(__MINGW64__)
1395
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab,
1396
                                                                uint64_t cd,
1397
                                                                uint64_t *hi) {
1398
  return umul128_generic(ab, cd, hi);
1399
}
1400
#endif // !__MINGW64__
1401
1402
#endif // FASTFLOAT_32BIT
1403
1404
// compute 64-bit a*b
1405
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
1406
26
full_multiplication(uint64_t a, uint64_t b) {
1407
26
  if (cpp20_and_in_constexpr()) {
1408
0
    value128 answer;
1409
0
    answer.low = umul128_generic(a, b, &answer.high);
1410
0
    return answer;
1411
0
  }
1412
26
  value128 answer;
1413
#if defined(_M_ARM64) && !defined(__MINGW32__)
1414
  // ARM64 has native support for 64-bit multiplications, no need to emulate
1415
  // But MinGW on ARM64 doesn't have native support for 64-bit multiplications
1416
  answer.high = __umulh(a, b);
1417
  answer.low = a * b;
1418
#elif defined(FASTFLOAT_32BIT) ||                                              \
1419
    (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64))
1420
  answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
1421
#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
1422
  __uint128_t r = ((__uint128_t)a) * b;
1423
26
  answer.low = uint64_t(r);
1424
26
  answer.high = uint64_t(r >> 64);
1425
#else
1426
  answer.low = umul128_generic(a, b, &answer.high);
1427
#endif
1428
26
  return answer;
1429
26
}
1430
1431
struct adjusted_mantissa {
1432
  uint64_t mantissa{0};
1433
  int32_t power2{0}; // a negative value indicates an invalid result
1434
60
  adjusted_mantissa() = default;
1435
1436
0
  constexpr bool operator==(adjusted_mantissa const &o) const {
1437
0
    return mantissa == o.mantissa && power2 == o.power2;
1438
0
  }
1439
1440
10
  constexpr bool operator!=(adjusted_mantissa const &o) const {
1441
10
    return mantissa != o.mantissa || power2 != o.power2;
1442
10
  }
1443
};
1444
1445
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
1446
constexpr static int32_t invalid_am_bias = -0x8000;
1447
1448
// used for binary_format_lookup_tables<T>::max_mantissa
1449
constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
1450
1451
template <typename T, typename U = void> struct binary_format_lookup_tables;
1452
1453
template <typename T> struct binary_format : binary_format_lookup_tables<T> {
1454
  using equiv_uint = equiv_uint_t<T>;
1455
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(); // used when fegetround() == FE_TONEAREST
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(); // used when fegetround() == FE_TONEAREST
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();
1475
};
1476
1477
template <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};
1481
1482
  // Largest integer value v so that (5**index * v) <= 1<<53.
1483
  // 0x20000000000000 == 1 << 53
1484
  static constexpr uint64_t max_mantissa[] = {
1485
      0x20000000000000,
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),
1501
      0x20000000000000 /
1502
          (constant_55555 * constant_55555 * constant_55555 * 5 * 5),
1503
      0x20000000000000 /
1504
          (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
1505
      0x20000000000000 /
1506
          (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5),
1507
      0x20000000000000 /
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)};
1517
};
1518
1519
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1520
1521
template <typename U>
1522
constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[];
1523
1524
template <typename U>
1525
constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[];
1526
1527
#endif
1528
1529
template <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};
1532
1533
  // Largest integer value v so that (5**index * v) <= 1<<24.
1534
  // 0x1000000 == 1<<24
1535
  static constexpr uint64_t max_mantissa[] = {
1536
      0x1000000,
1537
      0x1000000 / 5,
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)};
1548
};
1549
1550
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1551
1552
template <typename U>
1553
constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[];
1554
1555
template <typename U>
1556
constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[];
1557
1558
#endif
1559
1560
template <>
1561
2.84k
inline constexpr int binary_format<double>::min_exponent_fast_path() {
1562
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
1563
  return 0;
1564
#else
1565
2.84k
  return -22;
1566
2.84k
#endif
1567
2.84k
}
1568
1569
template <>
1570
0
inline constexpr int binary_format<float>::min_exponent_fast_path() {
1571
0
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
1572
0
  return 0;
1573
0
#else
1574
0
  return -10;
1575
0
#endif
1576
0
}
1577
1578
template <>
1579
2.92k
inline constexpr int binary_format<double>::mantissa_explicit_bits() {
1580
2.92k
  return 52;
1581
2.92k
}
1582
1583
template <>
1584
0
inline constexpr int binary_format<float>::mantissa_explicit_bits() {
1585
0
  return 23;
1586
0
}
1587
1588
template <>
1589
0
inline constexpr int binary_format<double>::max_exponent_round_to_even() {
1590
0
  return 23;
1591
0
}
1592
1593
template <>
1594
0
inline constexpr int binary_format<float>::max_exponent_round_to_even() {
1595
0
  return 10;
1596
0
}
1597
1598
template <>
1599
3
inline constexpr int binary_format<double>::min_exponent_round_to_even() {
1600
3
  return -4;
1601
3
}
1602
1603
template <>
1604
0
inline constexpr int binary_format<float>::min_exponent_round_to_even() {
1605
0
  return -17;
1606
0
}
1607
1608
25
template <> inline constexpr int binary_format<double>::minimum_exponent() {
1609
25
  return -1023;
1610
25
}
1611
1612
0
template <> inline constexpr int binary_format<float>::minimum_exponent() {
1613
0
  return -127;
1614
0
}
1615
1616
67
template <> inline constexpr int binary_format<double>::infinite_power() {
1617
67
  return 0x7FF;
1618
67
}
1619
1620
0
template <> inline constexpr int binary_format<float>::infinite_power() {
1621
0
  return 0xFF;
1622
0
}
1623
1624
50
template <> inline constexpr int binary_format<double>::sign_index() {
1625
50
  return 63;
1626
50
}
1627
1628
0
template <> inline constexpr int binary_format<float>::sign_index() {
1629
0
  return 31;
1630
0
}
1631
1632
template <>
1633
2.82k
inline constexpr int binary_format<double>::max_exponent_fast_path() {
1634
2.82k
  return 22;
1635
2.82k
}
1636
1637
template <>
1638
0
inline constexpr int binary_format<float>::max_exponent_fast_path() {
1639
0
  return 10;
1640
0
}
1641
1642
template <>
1643
2.79k
inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
1644
2.79k
  return uint64_t(2) << mantissa_explicit_bits();
1645
2.79k
}
1646
1647
template <>
1648
0
inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
1649
0
  return uint64_t(2) << mantissa_explicit_bits();
1650
0
}
1651
1652
// credit: Jakub Jelínek
1653
#ifdef __STDCPP_FLOAT16_T__
1654
template <typename U> struct binary_format_lookup_tables<std::float16_t, U> {
1655
  static constexpr std::float16_t powers_of_ten[] = {1e0f16, 1e1f16, 1e2f16,
1656
                                                     1e3f16, 1e4f16};
1657
1658
  // Largest integer value v so that (5**index * v) <= 1<<11.
1659
  // 0x800 == 1<<11
1660
  static constexpr uint64_t max_mantissa[] = {0x800,
1661
                                              0x800 / 5,
1662
                                              0x800 / (5 * 5),
1663
                                              0x800 / (5 * 5 * 5),
1664
                                              0x800 / (5 * 5 * 5 * 5),
1665
                                              0x800 / (constant_55555)};
1666
};
1667
1668
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1669
1670
template <typename U>
1671
constexpr std::float16_t
1672
    binary_format_lookup_tables<std::float16_t, U>::powers_of_ten[];
1673
1674
template <typename U>
1675
constexpr uint64_t
1676
    binary_format_lookup_tables<std::float16_t, U>::max_mantissa[];
1677
1678
#endif
1679
1680
template <>
1681
inline constexpr std::float16_t
1682
binary_format<std::float16_t>::exact_power_of_ten(int64_t power) {
1683
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1684
  return (void)powers_of_ten[0], powers_of_ten[power];
1685
}
1686
1687
template <>
1688
inline constexpr binary_format<std::float16_t>::equiv_uint
1689
binary_format<std::float16_t>::exponent_mask() {
1690
  return 0x7C00;
1691
}
1692
1693
template <>
1694
inline constexpr binary_format<std::float16_t>::equiv_uint
1695
binary_format<std::float16_t>::mantissa_mask() {
1696
  return 0x03FF;
1697
}
1698
1699
template <>
1700
inline constexpr binary_format<std::float16_t>::equiv_uint
1701
binary_format<std::float16_t>::hidden_bit_mask() {
1702
  return 0x0400;
1703
}
1704
1705
template <>
1706
inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() {
1707
  return 4;
1708
}
1709
1710
template <>
1711
inline constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() {
1712
  return 10;
1713
}
1714
1715
template <>
1716
inline constexpr uint64_t
1717
binary_format<std::float16_t>::max_mantissa_fast_path() {
1718
  return uint64_t(2) << mantissa_explicit_bits();
1719
}
1720
1721
template <>
1722
inline constexpr uint64_t
1723
binary_format<std::float16_t>::max_mantissa_fast_path(int64_t power) {
1724
  // caller is responsible to ensure that
1725
  // power >= 0 && power <= 4
1726
  //
1727
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1728
  return (void)max_mantissa[0], max_mantissa[power];
1729
}
1730
1731
template <>
1732
inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() {
1733
  return 0;
1734
}
1735
1736
template <>
1737
inline constexpr int
1738
binary_format<std::float16_t>::max_exponent_round_to_even() {
1739
  return 5;
1740
}
1741
1742
template <>
1743
inline constexpr int
1744
binary_format<std::float16_t>::min_exponent_round_to_even() {
1745
  return -22;
1746
}
1747
1748
template <>
1749
inline constexpr int binary_format<std::float16_t>::minimum_exponent() {
1750
  return -15;
1751
}
1752
1753
template <>
1754
inline constexpr int binary_format<std::float16_t>::infinite_power() {
1755
  return 0x1F;
1756
}
1757
1758
template <> inline constexpr int binary_format<std::float16_t>::sign_index() {
1759
  return 15;
1760
}
1761
1762
template <>
1763
inline constexpr int binary_format<std::float16_t>::largest_power_of_ten() {
1764
  return 4;
1765
}
1766
1767
template <>
1768
inline constexpr int binary_format<std::float16_t>::smallest_power_of_ten() {
1769
  return -27;
1770
}
1771
1772
template <>
1773
inline constexpr size_t binary_format<std::float16_t>::max_digits() {
1774
  return 22;
1775
}
1776
#endif // __STDCPP_FLOAT16_T__
1777
1778
// credit: Jakub Jelínek
1779
#ifdef __STDCPP_BFLOAT16_T__
1780
template <typename U> struct binary_format_lookup_tables<std::bfloat16_t, U> {
1781
  static constexpr std::bfloat16_t powers_of_ten[] = {1e0bf16, 1e1bf16, 1e2bf16,
1782
                                                      1e3bf16};
1783
1784
  // Largest integer value v so that (5**index * v) <= 1<<8.
1785
  // 0x100 == 1<<8
1786
  static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5),
1787
                                              0x100 / (5 * 5 * 5),
1788
                                              0x100 / (5 * 5 * 5 * 5)};
1789
};
1790
1791
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
1792
1793
template <typename U>
1794
constexpr std::bfloat16_t
1795
    binary_format_lookup_tables<std::bfloat16_t, U>::powers_of_ten[];
1796
1797
template <typename U>
1798
constexpr uint64_t
1799
    binary_format_lookup_tables<std::bfloat16_t, U>::max_mantissa[];
1800
1801
#endif
1802
1803
template <>
1804
inline constexpr std::bfloat16_t
1805
binary_format<std::bfloat16_t>::exact_power_of_ten(int64_t power) {
1806
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1807
  return (void)powers_of_ten[0], powers_of_ten[power];
1808
}
1809
1810
template <>
1811
inline constexpr int binary_format<std::bfloat16_t>::max_exponent_fast_path() {
1812
  return 3;
1813
}
1814
1815
template <>
1816
inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1817
binary_format<std::bfloat16_t>::exponent_mask() {
1818
  return 0x7F80;
1819
}
1820
1821
template <>
1822
inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1823
binary_format<std::bfloat16_t>::mantissa_mask() {
1824
  return 0x007F;
1825
}
1826
1827
template <>
1828
inline constexpr binary_format<std::bfloat16_t>::equiv_uint
1829
binary_format<std::bfloat16_t>::hidden_bit_mask() {
1830
  return 0x0080;
1831
}
1832
1833
template <>
1834
inline constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
1835
  return 7;
1836
}
1837
1838
template <>
1839
inline constexpr uint64_t
1840
binary_format<std::bfloat16_t>::max_mantissa_fast_path() {
1841
  return uint64_t(2) << mantissa_explicit_bits();
1842
}
1843
1844
template <>
1845
inline constexpr uint64_t
1846
binary_format<std::bfloat16_t>::max_mantissa_fast_path(int64_t power) {
1847
  // caller is responsible to ensure that
1848
  // power >= 0 && power <= 3
1849
  //
1850
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1851
  return (void)max_mantissa[0], max_mantissa[power];
1852
}
1853
1854
template <>
1855
inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() {
1856
  return 0;
1857
}
1858
1859
template <>
1860
inline constexpr int
1861
binary_format<std::bfloat16_t>::max_exponent_round_to_even() {
1862
  return 3;
1863
}
1864
1865
template <>
1866
inline constexpr int
1867
binary_format<std::bfloat16_t>::min_exponent_round_to_even() {
1868
  return -24;
1869
}
1870
1871
template <>
1872
inline constexpr int binary_format<std::bfloat16_t>::minimum_exponent() {
1873
  return -127;
1874
}
1875
1876
template <>
1877
inline constexpr int binary_format<std::bfloat16_t>::infinite_power() {
1878
  return 0xFF;
1879
}
1880
1881
template <> inline constexpr int binary_format<std::bfloat16_t>::sign_index() {
1882
  return 15;
1883
}
1884
1885
template <>
1886
inline constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() {
1887
  return 38;
1888
}
1889
1890
template <>
1891
inline constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() {
1892
  return -60;
1893
}
1894
1895
template <>
1896
inline constexpr size_t binary_format<std::bfloat16_t>::max_digits() {
1897
  return 98;
1898
}
1899
#endif // __STDCPP_BFLOAT16_T__
1900
1901
template <>
1902
inline constexpr uint64_t
1903
0
binary_format<double>::max_mantissa_fast_path(int64_t power) {
1904
  // caller is responsible to ensure that
1905
  // power >= 0 && power <= 22
1906
  //
1907
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1908
0
  return (void)max_mantissa[0], max_mantissa[power];
1909
0
}
1910
1911
template <>
1912
inline constexpr uint64_t
1913
0
binary_format<float>::max_mantissa_fast_path(int64_t power) {
1914
0
  // caller is responsible to ensure that
1915
0
  // power >= 0 && power <= 10
1916
0
  //
1917
0
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1918
0
  return (void)max_mantissa[0], max_mantissa[power];
1919
0
}
1920
1921
template <>
1922
inline constexpr double
1923
2.79k
binary_format<double>::exact_power_of_ten(int64_t power) {
1924
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1925
2.79k
  return (void)powers_of_ten[0], powers_of_ten[power];
1926
2.79k
}
1927
1928
template <>
1929
0
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
1930
0
  // Work around clang bug https://godbolt.org/z/zedh7rrhc
1931
0
  return (void)powers_of_ten[0], powers_of_ten[power];
1932
0
}
1933
1934
36
template <> inline constexpr int binary_format<double>::largest_power_of_ten() {
1935
36
  return 308;
1936
36
}
1937
1938
0
template <> inline constexpr int binary_format<float>::largest_power_of_ten() {
1939
0
  return 38;
1940
0
}
1941
1942
template <>
1943
55
inline constexpr int binary_format<double>::smallest_power_of_ten() {
1944
55
  return -342;
1945
55
}
1946
1947
0
template <> inline constexpr int binary_format<float>::smallest_power_of_ten() {
1948
0
  return -64;
1949
0
}
1950
1951
0
template <> inline constexpr size_t binary_format<double>::max_digits() {
1952
0
  return 769;
1953
0
}
1954
1955
0
template <> inline constexpr size_t binary_format<float>::max_digits() {
1956
0
  return 114;
1957
0
}
1958
1959
template <>
1960
inline constexpr binary_format<float>::equiv_uint
1961
0
binary_format<float>::exponent_mask() {
1962
0
  return 0x7F800000;
1963
0
}
1964
1965
template <>
1966
inline constexpr binary_format<double>::equiv_uint
1967
0
binary_format<double>::exponent_mask() {
1968
0
  return 0x7FF0000000000000;
1969
0
}
1970
1971
template <>
1972
inline constexpr binary_format<float>::equiv_uint
1973
0
binary_format<float>::mantissa_mask() {
1974
0
  return 0x007FFFFF;
1975
0
}
1976
1977
template <>
1978
inline constexpr binary_format<double>::equiv_uint
1979
0
binary_format<double>::mantissa_mask() {
1980
0
  return 0x000FFFFFFFFFFFFF;
1981
0
}
1982
1983
template <>
1984
inline constexpr binary_format<float>::equiv_uint
1985
0
binary_format<float>::hidden_bit_mask() {
1986
0
  return 0x00800000;
1987
0
}
1988
1989
template <>
1990
inline constexpr binary_format<double>::equiv_uint
1991
0
binary_format<double>::hidden_bit_mask() {
1992
0
  return 0x0010000000000000;
1993
0
}
1994
1995
template <typename T>
1996
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
1997
50
to_float(bool negative, adjusted_mantissa am, T &value) {
1998
50
  using equiv_uint = equiv_uint_t<T>;
1999
50
  equiv_uint word = equiv_uint(am.mantissa);
2000
50
  word = equiv_uint(word | equiv_uint(am.power2)
2001
50
                               << binary_format<T>::mantissa_explicit_bits());
2002
50
  word =
2003
50
      equiv_uint(word | equiv_uint(negative) << binary_format<T>::sign_index());
2004
#if FASTFLOAT_HAS_BIT_CAST
2005
  value = std::bit_cast<T>(word);
2006
#else
2007
50
  ::memcpy(&value, &word, sizeof(T));
2008
50
#endif
2009
50
}
2010
2011
template <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};
2024
};
2025
2026
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
2027
2028
template <typename T> constexpr bool space_lut<T>::value[];
2029
2030
#endif
2031
2032
0
template <typename UC> constexpr bool is_space(UC c) {
2033
0
  return c < 256 && space_lut<>::value[uint8_t(c)];
2034
0
}
2035
2036
0
template <typename UC> static constexpr uint64_t int_cmp_zeros() {
2037
0
  static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4),
2038
0
                "Unsupported character size");
2039
0
  return (sizeof(UC) == 1) ? 0x3030303030303030
2040
0
         : (sizeof(UC) == 2)
2041
0
             ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 |
2042
0
                uint64_t(UC('0')) << 16 | UC('0'))
2043
0
             : (uint64_t(UC('0')) << 32 | UC('0'));
2044
0
}
2045
2046
0
template <typename UC> static constexpr int int_cmp_len() {
2047
0
  return sizeof(uint64_t) / sizeof(UC);
2048
0
}
2049
2050
template <typename UC> constexpr UC const *str_const_nan();
2051
2052
311
template <> constexpr char const *str_const_nan<char>() { return "nan"; }
2053
2054
0
template <> constexpr wchar_t const *str_const_nan<wchar_t>() { return L"nan"; }
2055
2056
0
template <> constexpr char16_t const *str_const_nan<char16_t>() {
2057
0
  return u"nan";
2058
0
}
2059
2060
0
template <> constexpr char32_t const *str_const_nan<char32_t>() {
2061
0
  return U"nan";
2062
0
}
2063
2064
#ifdef __cpp_char8_t
2065
template <> constexpr char8_t const *str_const_nan<char8_t>() {
2066
  return u8"nan";
2067
}
2068
#endif
2069
2070
template <typename UC> constexpr UC const *str_const_inf();
2071
2072
311
template <> constexpr char const *str_const_inf<char>() { return "infinity"; }
2073
2074
0
template <> constexpr wchar_t const *str_const_inf<wchar_t>() {
2075
0
  return L"infinity";
2076
0
}
2077
2078
0
template <> constexpr char16_t const *str_const_inf<char16_t>() {
2079
0
  return u"infinity";
2080
0
}
2081
2082
0
template <> constexpr char32_t const *str_const_inf<char32_t>() {
2083
0
  return U"infinity";
2084
0
}
2085
2086
#ifdef __cpp_char8_t
2087
template <> constexpr char8_t const *str_const_inf<char8_t>() {
2088
  return u8"infinity";
2089
}
2090
#endif
2091
2092
template <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,
2111
      255};
2112
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};
2116
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};
2130
};
2131
2132
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
2133
2134
template <typename T> constexpr uint8_t int_luts<T>::chdigit[];
2135
2136
template <typename T> constexpr size_t int_luts<T>::maxdigits_u64[];
2137
2138
template <typename T> constexpr uint64_t int_luts<T>::min_safe_u64[];
2139
2140
#endif
2141
2142
template <typename UC>
2143
fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) {
2144
  return int_luts<>::chdigit[static_cast<unsigned char>(c)];
2145
}
2146
2147
0
fastfloat_really_inline constexpr size_t max_digits_u64(int base) {
2148
0
  return int_luts<>::maxdigits_u64[base - 2];
2149
0
}
2150
2151
// If a u64 is exactly max_digits_u64() in length, this is
2152
// the value below which it has definitely overflowed.
2153
0
fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) {
2154
0
  return int_luts<>::min_safe_u64[base - 2];
2155
0
}
2156
2157
static_assert(tinyobj_ff::is_same<equiv_uint_t<double>, uint64_t>::value,
2158
              "equiv_uint should be uint64_t for double");
2159
static_assert(std::numeric_limits<double>::is_iec559,
2160
              "double must fulfill the requirements of IEC 559 (IEEE 754)");
2161
2162
static_assert(tinyobj_ff::is_same<equiv_uint_t<float>, uint32_t>::value,
2163
              "equiv_uint should be uint32_t for float");
2164
static_assert(std::numeric_limits<float>::is_iec559,
2165
              "float must fulfill the requirements of IEC 559 (IEEE 754)");
2166
2167
#ifdef __STDCPP_FLOAT64_T__
2168
static_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");
2170
static_assert(
2171
    std::numeric_limits<std::float64_t>::is_iec559,
2172
    "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)");
2173
#endif // __STDCPP_FLOAT64_T__
2174
2175
#ifdef __STDCPP_FLOAT32_T__
2176
static_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");
2178
static_assert(
2179
    std::numeric_limits<std::float32_t>::is_iec559,
2180
    "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)");
2181
#endif // __STDCPP_FLOAT32_T__
2182
2183
#ifdef __STDCPP_FLOAT16_T__
2184
static_assert(
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");
2187
static_assert(
2188
    std::numeric_limits<std::float16_t>::is_iec559,
2189
    "std::float16_t must fulfill the requirements of IEC 559 (IEEE 754)");
2190
#endif // __STDCPP_FLOAT16_T__
2191
2192
#ifdef __STDCPP_BFLOAT16_T__
2193
static_assert(
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");
2196
static_assert(
2197
    std::numeric_limits<std::bfloat16_t>::is_iec559,
2198
    "std::bfloat16_t must fulfill the requirements of IEC 559 (IEEE 754)");
2199
#endif // __STDCPP_BFLOAT16_T__
2200
2201
0
constexpr chars_format operator~(chars_format rhs) noexcept {
2202
0
  using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2203
0
  return static_cast<chars_format>(~static_cast<int_type>(rhs));
2204
0
}
2205
2206
29.1k
constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept {
2207
29.1k
  using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2208
29.1k
  return static_cast<chars_format>(static_cast<int_type>(lhs) &
2209
29.1k
                                   static_cast<int_type>(rhs));
2210
29.1k
}
2211
2212
5.14k
constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept {
2213
5.14k
  using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2214
5.14k
  return static_cast<chars_format>(static_cast<int_type>(lhs) |
2215
5.14k
                                   static_cast<int_type>(rhs));
2216
5.14k
}
2217
2218
0
constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept {
2219
0
  using int_type = tinyobj_ff::underlying_type<chars_format>::type;
2220
0
  return static_cast<chars_format>(static_cast<int_type>(lhs) ^
2221
0
                                   static_cast<int_type>(rhs));
2222
0
}
2223
2224
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2225
0
operator&=(chars_format &lhs, chars_format rhs) noexcept {
2226
0
  return lhs = (lhs & rhs);
2227
0
}
2228
2229
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2230
0
operator|=(chars_format &lhs, chars_format rhs) noexcept {
2231
0
  return lhs = (lhs | rhs);
2232
0
}
2233
2234
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format &
2235
0
operator^=(chars_format &lhs, chars_format rhs) noexcept {
2236
0
  return lhs = (lhs ^ rhs);
2237
0
}
2238
2239
namespace detail {
2240
// adjust for deprecated feature macros
2241
10.2k
constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
2242
10.2k
  return fmt
2243
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS
2244
         | chars_format::allow_leading_plus
2245
#endif
2246
#ifdef FASTFLOAT_SKIP_WHITE_SPACE
2247
         | chars_format::skip_white_space
2248
#endif
2249
10.2k
      ;
2250
10.2k
}
2251
} // namespace detail
2252
2253
} // namespace fast_float
2254
2255
#endif
2256
2257
2258
#ifndef FASTFLOAT_FAST_FLOAT_H
2259
#define FASTFLOAT_FAST_FLOAT_H
2260
2261
2262
namespace fast_float {
2263
/**
2264
 * This function parses the character sequence [first,last) for a number. It
2265
 * parses floating-point numbers expecting a locale-indepent format equivalent
2266
 * to what is used by std::strtod in the default ("C") locale. The resulting
2267
 * floating-point value is the closest floating-point values (using either float
2268
 * or double), using the "round to even" convention for values that would
2269
 * otherwise fall right in-between two values. That is, we provide exact parsing
2270
 * according to the IEEE standard.
2271
 *
2272
 * Given a successful parse, the pointer (`ptr`) in the returned value is set to
2273
 * point right after the parsed number, and the `value` referenced is set to the
2274
 * parsed value. In case of error, the returned `ec` contains a representative
2275
 * error, otherwise the default (`tinyobj_ff::ff_errc()`) value is stored.
2276
 *
2277
 * The implementation does not throw and does not allocate memory (e.g., with
2278
 * `new` or `malloc`).
2279
 *
2280
 * Like the C++17 standard, the `fast_float::from_chars` functions take an
2281
 * optional last argument of the type `fast_float::chars_format`. It is a bitset
2282
 * value: we check whether `fmt & fast_float::chars_format::fixed` and `fmt &
2283
 * fast_float::chars_format::scientific` are set to determine whether we allow
2284
 * the fixed point and scientific notation respectively. The default is
2285
 * `fast_float::chars_format::general` which allows both `fixed` and
2286
 * `scientific`.
2287
 */
2288
template <typename T, typename UC = char,
2289
          typename = FASTFLOAT_ENABLE_IF(is_supported_float_type<T>::value)>
2290
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2291
from_chars(UC const *first, UC const *last, T &value,
2292
           chars_format fmt = chars_format::general) noexcept;
2293
2294
/**
2295
 * Like from_chars, but accepts an `options` argument to govern number parsing.
2296
 * Both for floating-point types and integer types.
2297
 */
2298
template <typename T, typename UC = char>
2299
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2300
from_chars_advanced(UC const *first, UC const *last, T &value,
2301
                    parse_options_t<UC> options) noexcept;
2302
2303
/**
2304
 * from_chars for integer types.
2305
 */
2306
template <typename T, typename UC = char,
2307
          typename = FASTFLOAT_ENABLE_IF(is_supported_integer_type<T>::value)>
2308
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2309
from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept;
2310
2311
} // namespace fast_float
2312
2313
#endif // FASTFLOAT_FAST_FLOAT_H
2314
2315
#ifndef FASTFLOAT_ASCII_NUMBER_H
2316
#define FASTFLOAT_ASCII_NUMBER_H
2317
2318
#include <cctype>
2319
#include <cstring>
2320
#include <limits>
2321
2322
2323
#ifdef FASTFLOAT_SSE2
2324
#include <emmintrin.h>
2325
#endif
2326
2327
#ifdef FASTFLOAT_NEON
2328
#include <arm_neon.h>
2329
#endif
2330
2331
namespace fast_float {
2332
2333
0
template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
2334
0
#ifdef FASTFLOAT_HAS_SIMD
2335
0
  return tinyobj_ff::is_same<UC, char16_t>::value;
2336
0
#else
2337
0
  return false;
2338
0
#endif
2339
0
}
2340
2341
// Next function can be micro-optimized, but compilers are entirely
2342
// able to optimize it well.
2343
template <typename UC>
2344
102k
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
2345
102k
  return !(c > UC('9') || c < UC('0'));
2346
102k
}
2347
2348
0
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
2349
0
  return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 |
2350
0
         (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 |
2351
0
         (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 |
2352
0
         (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56;
2353
0
}
2354
2355
// Read 8 UC into a u64. Truncates UC if not char.
2356
template <typename UC>
2357
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
2358
403
read8_to_u64(UC const *chars) {
2359
403
  if (cpp20_and_in_constexpr() || !tinyobj_ff::is_same<UC, char>::value) {
2360
0
    uint64_t val = 0;
2361
0
    for (int i = 0; i < 8; ++i) {
2362
0
      val |= uint64_t(uint8_t(*chars)) << (i * 8);
2363
0
      ++chars;
2364
0
    }
2365
0
    return val;
2366
0
  }
2367
403
  uint64_t val;
2368
403
  ::memcpy(&val, chars, sizeof(uint64_t));
2369
#if FASTFLOAT_IS_BIG_ENDIAN == 1
2370
  // Need to read as-if the number was in little-endian order.
2371
  val = byteswap(val);
2372
#endif
2373
403
  return val;
2374
403
}
2375
2376
#ifdef FASTFLOAT_SSE2
2377
2378
0
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
2379
0
  FASTFLOAT_SIMD_DISABLE_WARNINGS
2380
0
  __m128i const packed = _mm_packus_epi16(data, data);
2381
0
#ifdef FASTFLOAT_64BIT
2382
0
  return uint64_t(_mm_cvtsi128_si64(packed));
2383
0
#else
2384
0
  uint64_t value;
2385
0
  // Visual Studio + older versions of GCC don't support _mm_storeu_si64
2386
0
  _mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed);
2387
0
  return value;
2388
0
#endif
2389
0
  FASTFLOAT_SIMD_RESTORE_WARNINGS
2390
0
}
2391
2392
0
fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
2393
0
  FASTFLOAT_SIMD_DISABLE_WARNINGS
2394
0
  return simd_read8_to_u64(
2395
0
      _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)));
2396
0
  FASTFLOAT_SIMD_RESTORE_WARNINGS
2397
0
}
2398
2399
#elif defined(FASTFLOAT_NEON)
2400
2401
fastfloat_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
2406
}
2407
2408
fastfloat_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
2413
}
2414
2415
#endif // FASTFLOAT_SSE2
2416
2417
// MSVC SFINAE is broken pre-VS2017
2418
#if defined(_MSC_VER) && _MSC_VER <= 1900
2419
template <typename UC>
2420
#else
2421
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
2422
#endif
2423
// dummy for compile
2424
0
uint64_t simd_read8_to_u64(UC const *) {
2425
0
  return 0;
2426
0
}
2427
2428
// credit  @aqrit
2429
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
2430
190
parse_eight_digits_unrolled(uint64_t val) {
2431
190
  uint64_t const mask = 0x000000FF000000FF;
2432
190
  uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
2433
190
  uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
2434
190
  val -= 0x3030303030303030;
2435
190
  val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
2436
190
  val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
2437
190
  return uint32_t(val);
2438
190
}
2439
2440
// Call this if chars are definitely 8 digits.
2441
template <typename UC>
2442
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
2443
0
parse_eight_digits_unrolled(UC const *chars) noexcept {
2444
0
  if (cpp20_and_in_constexpr() || !has_simd_opt<UC>()) {
2445
0
    return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay
2446
0
  }
2447
0
  return parse_eight_digits_unrolled(simd_read8_to_u64(chars));
2448
0
}
2449
2450
// credit @aqrit
2451
fastfloat_really_inline constexpr bool
2452
213
is_made_of_eight_digits_fast(uint64_t val) noexcept {
2453
213
  return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
2454
213
            0x8080808080808080));
2455
213
}
2456
2457
#ifdef FASTFLOAT_HAS_SIMD
2458
2459
// Call this if chars might not be 8 digits.
2460
// Using this style (instead of is_made_of_eight_digits_fast() then
2461
// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice.
2462
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
2463
simd_parse_if_eight_digits_unrolled(char16_t const *chars,
2464
0
                                    uint64_t &i) noexcept {
2465
0
  if (cpp20_and_in_constexpr()) {
2466
0
    return false;
2467
0
  }
2468
0
#ifdef FASTFLOAT_SSE2
2469
0
  FASTFLOAT_SIMD_DISABLE_WARNINGS
2470
0
  __m128i const data =
2471
0
      _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars));
2472
0
2473
0
  // (x - '0') <= 9
2474
0
  // http://0x80.pl/articles/simd-parsing-int-sequences.html
2475
0
  __m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720));
2476
0
  __m128i const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759));
2477
0
2478
0
  if (_mm_movemask_epi8(t1) == 0) {
2479
0
    i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
2480
0
    return true;
2481
0
  } else
2482
0
    return false;
2483
0
  FASTFLOAT_SIMD_RESTORE_WARNINGS
2484
0
#elif defined(FASTFLOAT_NEON)
2485
0
  FASTFLOAT_SIMD_DISABLE_WARNINGS
2486
0
  uint16x8_t const data = vld1q_u16(reinterpret_cast<uint16_t const *>(chars));
2487
0
2488
0
  // (x - '0') <= 9
2489
0
  // http://0x80.pl/articles/simd-parsing-int-sequences.html
2490
0
  uint16x8_t const t0 = vsubq_u16(data, vmovq_n_u16('0'));
2491
0
  uint16x8_t const mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1));
2492
0
2493
0
  if (vminvq_u16(mask) == 0xFFFF) {
2494
0
    i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
2495
0
    return true;
2496
0
  } else
2497
0
    return false;
2498
0
  FASTFLOAT_SIMD_RESTORE_WARNINGS
2499
0
#else
2500
0
  (void)chars;
2501
0
  (void)i;
2502
0
  return false;
2503
0
#endif // FASTFLOAT_SSE2
2504
0
}
2505
2506
#endif // FASTFLOAT_HAS_SIMD
2507
2508
// MSVC SFINAE is broken pre-VS2017
2509
#if defined(_MSC_VER) && _MSC_VER <= 1900
2510
template <typename UC>
2511
#else
2512
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
2513
#endif
2514
// dummy for compile
2515
bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) {
2516
  return 0;
2517
}
2518
2519
template <typename UC, FASTFLOAT_ENABLE_IF(!tinyobj_ff::is_same<UC, char>::value) = 0>
2520
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
2521
loop_parse_if_eight_digits(UC const *&p, UC const *const pend, uint64_t &i) {
2522
  if (!has_simd_opt<UC>()) {
2523
    return;
2524
  }
2525
  while ((tinyobj_ff::distance(p, pend) >= 8) &&
2526
         simd_parse_if_eight_digits_unrolled(
2527
             p, i)) { // in rare cases, this will overflow, but that's ok
2528
    p += 8;
2529
  }
2530
}
2531
2532
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
2533
loop_parse_if_eight_digits(char const *&p, char const *const pend,
2534
412
                           uint64_t &i) {
2535
  // optimizes better than parse_if_eight_digits_unrolled() for UC = char.
2536
602
  while ((tinyobj_ff::distance(p, pend) >= 8) &&
2537
213
         is_made_of_eight_digits_fast(read8_to_u64(p))) {
2538
190
    i = i * 100000000 +
2539
190
        parse_eight_digits_unrolled(read8_to_u64(
2540
190
            p)); // in rare cases, this will overflow, but that's ok
2541
190
    p += 8;
2542
190
  }
2543
412
}
2544
2545
enum class parse_error {
2546
  no_error,
2547
  // [JSON-only] The minus sign must be followed by an integer.
2548
  missing_integer_after_sign,
2549
  // A sign must be followed by an integer or dot.
2550
  missing_integer_or_dot_after_sign,
2551
  // [JSON-only] The integer part must not have leading zeros.
2552
  leading_zeros_in_integer_part,
2553
  // [JSON-only] The integer part must have at least one digit.
2554
  no_digits_in_integer_part,
2555
  // [JSON-only] If there is a decimal point, there must be digits in the
2556
  // fractional part.
2557
  no_digits_in_fractional_part,
2558
  // The mantissa must have at least one digit.
2559
  no_digits_in_mantissa,
2560
  // Scientific notation requires an exponential part.
2561
  missing_exponential_part,
2562
};
2563
2564
template <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};
2569
  bool valid{false};
2570
  bool too_many_digits{false};
2571
  // contains the range of the significant digits
2572
  span<UC const> integer{};  // non-nullable
2573
  span<UC const> fraction{}; // nullable
2574
  parse_error error{parse_error::no_error};
2575
};
2576
2577
using byte_span = span<char const>;
2578
using parsed_number_string = parsed_number_string_t<char>;
2579
2580
template <typename UC>
2581
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
2582
2.29k
report_parse_error(UC const *p, parse_error error) {
2583
2.29k
  parsed_number_string_t<UC> answer;
2584
2.29k
  answer.valid = false;
2585
2.29k
  answer.lastmatch = p;
2586
2.29k
  answer.error = error;
2587
2.29k
  return answer;
2588
2.29k
}
2589
2590
// Assuming that you use no more than 19 digits, this will
2591
// parse an ASCII string.
2592
template <bool basic_json_fmt, typename UC>
2593
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
2594
parse_number_string(UC const *p, UC const *pend,
2595
5.14k
                    parse_options_t<UC> options) noexcept {
2596
5.14k
  chars_format const fmt = detail::adjust_for_feature_macros(options.format);
2597
5.14k
  UC const decimal_point = options.decimal_point;
2598
2599
5.14k
  parsed_number_string_t<UC> answer;
2600
5.14k
  answer.valid = false;
2601
5.14k
  answer.too_many_digits = false;
2602
  // assume p < pend, so dereference without checks;
2603
5.14k
  answer.negative = (*p == UC('-'));
2604
  // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
2605
5.14k
  if ((*p == UC('-')) || (uint64_t(fmt & chars_format::allow_leading_plus) &&
2606
4.69k
                          !basic_json_fmt && *p == UC('+'))) {
2607
479
    ++p;
2608
479
    if (p == pend) {
2609
354
      return report_parse_error<UC>(
2610
354
          p, parse_error::missing_integer_or_dot_after_sign);
2611
354
    }
2612
125
    FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2613
0
      if (!is_integer(*p)) { // a sign must be followed by an integer
2614
0
        return report_parse_error<UC>(p,
2615
0
                                      parse_error::missing_integer_after_sign);
2616
0
      }
2617
0
    }
2618
125
    else {
2619
125
      if (!is_integer(*p) &&
2620
106
          (*p !=
2621
106
           decimal_point)) { // a sign must be followed by an integer or the dot
2622
98
        return report_parse_error<UC>(
2623
98
            p, parse_error::missing_integer_or_dot_after_sign);
2624
98
      }
2625
125
    }
2626
125
  }
2627
4.68k
  UC const *const start_digits = p;
2628
2629
4.68k
  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
2630
2631
54.3k
  while ((p != pend) && is_integer(*p)) {
2632
    // a multiplication by 10 is cheaper than an arbitrary integer
2633
    // multiplication
2634
49.6k
    i = 10 * i +
2635
49.6k
        uint64_t(*p -
2636
49.6k
                 UC('0')); // might overflow, we will handle the overflow later
2637
49.6k
    ++p;
2638
49.6k
  }
2639
4.68k
  UC const *const end_of_integer_part = p;
2640
4.68k
  int64_t digit_count = int64_t(end_of_integer_part - start_digits);
2641
4.68k
  answer.integer = span<UC const>(start_digits, size_t(digit_count));
2642
4.68k
  FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2643
    // at least 1 digit in integer part, without leading zeros
2644
0
    if (digit_count == 0) {
2645
0
      return report_parse_error<UC>(p, parse_error::no_digits_in_integer_part);
2646
0
    }
2647
0
    if ((start_digits[0] == UC('0') && digit_count > 1)) {
2648
0
      return report_parse_error<UC>(start_digits,
2649
0
                                    parse_error::leading_zeros_in_integer_part);
2650
0
    }
2651
0
  }
2652
2653
4.68k
  int64_t exponent = 0;
2654
4.68k
  bool const has_decimal_point = (p != pend) && (*p == decimal_point);
2655
4.68k
  if (has_decimal_point) {
2656
412
    ++p;
2657
412
    UC const *before = p;
2658
    // can occur at most twice without overflowing, but let it occur more, since
2659
    // for integers with many digits, digit parsing is the primary bottleneck.
2660
412
    loop_parse_if_eight_digits(p, pend, i);
2661
2662
752
    while ((p != pend) && is_integer(*p)) {
2663
340
      uint8_t digit = uint8_t(*p - UC('0'));
2664
340
      ++p;
2665
340
      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
2666
340
    }
2667
412
    exponent = before - p;
2668
412
    answer.fraction = span<UC const>(before, size_t(p - before));
2669
412
    digit_count -= exponent;
2670
412
  }
2671
4.68k
  FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2672
    // at least 1 digit in fractional part
2673
0
    if (has_decimal_point && exponent == 0) {
2674
0
      return report_parse_error<UC>(p,
2675
0
                                    parse_error::no_digits_in_fractional_part);
2676
0
    }
2677
0
  }
2678
4.68k
  else if (digit_count == 0) { // we must have encountered at least one integer!
2679
1.84k
    return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
2680
1.84k
  }
2681
2.84k
  int64_t exp_number = 0; // explicit exponential part
2682
2.84k
  if ((uint64_t(fmt & chars_format::scientific) && (p != pend) &&
2683
1.08k
       ((UC('e') == *p) || (UC('E') == *p))) ||
2684
2.22k
      (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) &&
2685
0
       ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) ||
2686
627
        (UC('D') == *p)))) {
2687
627
    UC const *location_of_e = p;
2688
627
    if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) ||
2689
627
        (UC('D') == *p)) {
2690
627
      ++p;
2691
627
    }
2692
627
    bool neg_exp = false;
2693
627
    if ((p != pend) && (UC('-') == *p)) {
2694
46
      neg_exp = true;
2695
46
      ++p;
2696
581
    } else if ((p != pend) &&
2697
180
               (UC('+') ==
2698
180
                *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
2699
93
      ++p;
2700
93
    }
2701
627
    if ((p == pend) || !is_integer(*p)) {
2702
519
      if (!uint64_t(fmt & chars_format::fixed)) {
2703
        // The exponential part is invalid for scientific notation, so it must
2704
        // be a trailing token for fixed notation. However, fixed notation is
2705
        // disabled, so report a scientific notation error.
2706
0
        return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2707
0
      }
2708
      // Otherwise, we will be ignoring the 'e'.
2709
519
      p = location_of_e;
2710
519
    } else {
2711
48.8k
      while ((p != pend) && is_integer(*p)) {
2712
48.7k
        uint8_t digit = uint8_t(*p - UC('0'));
2713
48.7k
        if (exp_number < 0x10000000) {
2714
48.7k
          exp_number = 10 * exp_number + digit;
2715
48.7k
        }
2716
48.7k
        ++p;
2717
48.7k
      }
2718
108
      if (neg_exp) {
2719
31
        exp_number = -exp_number;
2720
31
      }
2721
108
      exponent += exp_number;
2722
108
    }
2723
2.22k
  } else {
2724
    // If it scientific and not fixed, we have to bail out.
2725
2.22k
    if (uint64_t(fmt & chars_format::scientific) &&
2726
2.22k
        !uint64_t(fmt & chars_format::fixed)) {
2727
0
      return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2728
0
    }
2729
2.22k
  }
2730
2.84k
  answer.lastmatch = p;
2731
2.84k
  answer.valid = true;
2732
2733
  // If we frequently had to deal with long strings of digits,
2734
  // we could extend our code by using a 128-bit integer instead
2735
  // of a 64-bit integer. However, this is uncommon.
2736
  //
2737
  // We can deal with up to 19 digits.
2738
2.84k
  if (digit_count > 19) { // this is uncommon
2739
    // It is possible that the integer had an overflow.
2740
    // We have to handle the case where we have 0.0000somenumber.
2741
    // We need to be mindful of the case where we only have zeroes...
2742
    // E.g., 0.000000000...000.
2743
15
    UC const *start = start_digits;
2744
46.6k
    while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
2745
46.6k
      if (*start == UC('0')) {
2746
46.6k
        digit_count--;
2747
46.6k
      }
2748
46.6k
      start++;
2749
46.6k
    }
2750
2751
15
    if (digit_count > 19) {
2752
10
      answer.too_many_digits = true;
2753
      // Let us start again, this time, avoiding overflows.
2754
      // We don't need to check if is_integer, since we use the
2755
      // pre-tokenized spans from above.
2756
10
      i = 0;
2757
10
      p = answer.integer.ptr;
2758
10
      UC const *int_end = p + answer.integer.len();
2759
10
      uint64_t const minimal_nineteen_digit_integer{1000000000000000000};
2760
950
      while ((i < minimal_nineteen_digit_integer) && (p != int_end)) {
2761
940
        i = i * 10 + uint64_t(*p - UC('0'));
2762
940
        ++p;
2763
940
      }
2764
10
      if (i >= minimal_nineteen_digit_integer) { // We have a big integers
2765
5
        exponent = end_of_integer_part - p + exp_number;
2766
5
      } else { // We have a value with a fractional component.
2767
5
        p = answer.fraction.ptr;
2768
5
        UC const *frac_end = p + answer.fraction.len();
2769
214
        while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
2770
209
          i = i * 10 + uint64_t(*p - UC('0'));
2771
209
          ++p;
2772
209
        }
2773
5
        exponent = answer.fraction.ptr - p + exp_number;
2774
5
      }
2775
      // We have now corrected both exponent and i, to a truncated value
2776
10
    }
2777
15
  }
2778
2.84k
  answer.exponent = exponent;
2779
2.84k
  answer.mantissa = i;
2780
2.84k
  return answer;
2781
2.84k
}
Unexecuted instantiation: fast_float::parsed_number_string_t<char> fast_float::parse_number_string<true, char>(char const*, char const*, fast_float::parse_options_t<char>)
fast_float::parsed_number_string_t<char> fast_float::parse_number_string<false, char>(char const*, char const*, fast_float::parse_options_t<char>)
Line
Count
Source
2595
5.14k
                    parse_options_t<UC> options) noexcept {
2596
5.14k
  chars_format const fmt = detail::adjust_for_feature_macros(options.format);
2597
5.14k
  UC const decimal_point = options.decimal_point;
2598
2599
5.14k
  parsed_number_string_t<UC> answer;
2600
5.14k
  answer.valid = false;
2601
5.14k
  answer.too_many_digits = false;
2602
  // assume p < pend, so dereference without checks;
2603
5.14k
  answer.negative = (*p == UC('-'));
2604
  // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
2605
5.14k
  if ((*p == UC('-')) || (uint64_t(fmt & chars_format::allow_leading_plus) &&
2606
4.69k
                          !basic_json_fmt && *p == UC('+'))) {
2607
479
    ++p;
2608
479
    if (p == pend) {
2609
354
      return report_parse_error<UC>(
2610
354
          p, parse_error::missing_integer_or_dot_after_sign);
2611
354
    }
2612
125
    FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2613
0
      if (!is_integer(*p)) { // a sign must be followed by an integer
2614
0
        return report_parse_error<UC>(p,
2615
0
                                      parse_error::missing_integer_after_sign);
2616
0
      }
2617
0
    }
2618
125
    else {
2619
125
      if (!is_integer(*p) &&
2620
106
          (*p !=
2621
106
           decimal_point)) { // a sign must be followed by an integer or the dot
2622
98
        return report_parse_error<UC>(
2623
98
            p, parse_error::missing_integer_or_dot_after_sign);
2624
98
      }
2625
125
    }
2626
125
  }
2627
4.68k
  UC const *const start_digits = p;
2628
2629
4.68k
  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
2630
2631
54.3k
  while ((p != pend) && is_integer(*p)) {
2632
    // a multiplication by 10 is cheaper than an arbitrary integer
2633
    // multiplication
2634
49.6k
    i = 10 * i +
2635
49.6k
        uint64_t(*p -
2636
49.6k
                 UC('0')); // might overflow, we will handle the overflow later
2637
49.6k
    ++p;
2638
49.6k
  }
2639
4.68k
  UC const *const end_of_integer_part = p;
2640
4.68k
  int64_t digit_count = int64_t(end_of_integer_part - start_digits);
2641
4.68k
  answer.integer = span<UC const>(start_digits, size_t(digit_count));
2642
4.68k
  FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2643
    // at least 1 digit in integer part, without leading zeros
2644
0
    if (digit_count == 0) {
2645
0
      return report_parse_error<UC>(p, parse_error::no_digits_in_integer_part);
2646
0
    }
2647
0
    if ((start_digits[0] == UC('0') && digit_count > 1)) {
2648
0
      return report_parse_error<UC>(start_digits,
2649
0
                                    parse_error::leading_zeros_in_integer_part);
2650
0
    }
2651
0
  }
2652
2653
4.68k
  int64_t exponent = 0;
2654
4.68k
  bool const has_decimal_point = (p != pend) && (*p == decimal_point);
2655
4.68k
  if (has_decimal_point) {
2656
412
    ++p;
2657
412
    UC const *before = p;
2658
    // can occur at most twice without overflowing, but let it occur more, since
2659
    // for integers with many digits, digit parsing is the primary bottleneck.
2660
412
    loop_parse_if_eight_digits(p, pend, i);
2661
2662
752
    while ((p != pend) && is_integer(*p)) {
2663
340
      uint8_t digit = uint8_t(*p - UC('0'));
2664
340
      ++p;
2665
340
      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
2666
340
    }
2667
412
    exponent = before - p;
2668
412
    answer.fraction = span<UC const>(before, size_t(p - before));
2669
412
    digit_count -= exponent;
2670
412
  }
2671
4.68k
  FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
2672
    // at least 1 digit in fractional part
2673
0
    if (has_decimal_point && exponent == 0) {
2674
0
      return report_parse_error<UC>(p,
2675
0
                                    parse_error::no_digits_in_fractional_part);
2676
0
    }
2677
0
  }
2678
4.68k
  else if (digit_count == 0) { // we must have encountered at least one integer!
2679
1.84k
    return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
2680
1.84k
  }
2681
2.84k
  int64_t exp_number = 0; // explicit exponential part
2682
2.84k
  if ((uint64_t(fmt & chars_format::scientific) && (p != pend) &&
2683
1.08k
       ((UC('e') == *p) || (UC('E') == *p))) ||
2684
2.22k
      (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) &&
2685
0
       ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) ||
2686
627
        (UC('D') == *p)))) {
2687
627
    UC const *location_of_e = p;
2688
627
    if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) ||
2689
627
        (UC('D') == *p)) {
2690
627
      ++p;
2691
627
    }
2692
627
    bool neg_exp = false;
2693
627
    if ((p != pend) && (UC('-') == *p)) {
2694
46
      neg_exp = true;
2695
46
      ++p;
2696
581
    } else if ((p != pend) &&
2697
180
               (UC('+') ==
2698
180
                *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
2699
93
      ++p;
2700
93
    }
2701
627
    if ((p == pend) || !is_integer(*p)) {
2702
519
      if (!uint64_t(fmt & chars_format::fixed)) {
2703
        // The exponential part is invalid for scientific notation, so it must
2704
        // be a trailing token for fixed notation. However, fixed notation is
2705
        // disabled, so report a scientific notation error.
2706
0
        return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2707
0
      }
2708
      // Otherwise, we will be ignoring the 'e'.
2709
519
      p = location_of_e;
2710
519
    } else {
2711
48.8k
      while ((p != pend) && is_integer(*p)) {
2712
48.7k
        uint8_t digit = uint8_t(*p - UC('0'));
2713
48.7k
        if (exp_number < 0x10000000) {
2714
48.7k
          exp_number = 10 * exp_number + digit;
2715
48.7k
        }
2716
48.7k
        ++p;
2717
48.7k
      }
2718
108
      if (neg_exp) {
2719
31
        exp_number = -exp_number;
2720
31
      }
2721
108
      exponent += exp_number;
2722
108
    }
2723
2.22k
  } else {
2724
    // If it scientific and not fixed, we have to bail out.
2725
2.22k
    if (uint64_t(fmt & chars_format::scientific) &&
2726
2.22k
        !uint64_t(fmt & chars_format::fixed)) {
2727
0
      return report_parse_error<UC>(p, parse_error::missing_exponential_part);
2728
0
    }
2729
2.22k
  }
2730
2.84k
  answer.lastmatch = p;
2731
2.84k
  answer.valid = true;
2732
2733
  // If we frequently had to deal with long strings of digits,
2734
  // we could extend our code by using a 128-bit integer instead
2735
  // of a 64-bit integer. However, this is uncommon.
2736
  //
2737
  // We can deal with up to 19 digits.
2738
2.84k
  if (digit_count > 19) { // this is uncommon
2739
    // It is possible that the integer had an overflow.
2740
    // We have to handle the case where we have 0.0000somenumber.
2741
    // We need to be mindful of the case where we only have zeroes...
2742
    // E.g., 0.000000000...000.
2743
15
    UC const *start = start_digits;
2744
46.6k
    while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
2745
46.6k
      if (*start == UC('0')) {
2746
46.6k
        digit_count--;
2747
46.6k
      }
2748
46.6k
      start++;
2749
46.6k
    }
2750
2751
15
    if (digit_count > 19) {
2752
10
      answer.too_many_digits = true;
2753
      // Let us start again, this time, avoiding overflows.
2754
      // We don't need to check if is_integer, since we use the
2755
      // pre-tokenized spans from above.
2756
10
      i = 0;
2757
10
      p = answer.integer.ptr;
2758
10
      UC const *int_end = p + answer.integer.len();
2759
10
      uint64_t const minimal_nineteen_digit_integer{1000000000000000000};
2760
950
      while ((i < minimal_nineteen_digit_integer) && (p != int_end)) {
2761
940
        i = i * 10 + uint64_t(*p - UC('0'));
2762
940
        ++p;
2763
940
      }
2764
10
      if (i >= minimal_nineteen_digit_integer) { // We have a big integers
2765
5
        exponent = end_of_integer_part - p + exp_number;
2766
5
      } else { // We have a value with a fractional component.
2767
5
        p = answer.fraction.ptr;
2768
5
        UC const *frac_end = p + answer.fraction.len();
2769
214
        while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
2770
209
          i = i * 10 + uint64_t(*p - UC('0'));
2771
209
          ++p;
2772
209
        }
2773
5
        exponent = answer.fraction.ptr - p + exp_number;
2774
5
      }
2775
      // We have now corrected both exponent and i, to a truncated value
2776
10
    }
2777
15
  }
2778
2.84k
  answer.exponent = exponent;
2779
2.84k
  answer.mantissa = i;
2780
2.84k
  return answer;
2781
2.84k
}
2782
2783
template <typename T, typename UC>
2784
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
2785
parse_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;
2789
2790
  from_chars_result_t<UC> answer;
2791
2792
  UC const *const first = p;
2793
2794
  bool const negative = (*p == UC('-'));
2795
#ifdef FASTFLOAT_VISUAL_STUDIO
2796
#pragma warning(push)
2797
#pragma warning(disable : 4127)
2798
#endif
2799
  if (!tinyobj_ff::is_signed<T>::value && negative) {
2800
#ifdef FASTFLOAT_VISUAL_STUDIO
2801
#pragma warning(pop)
2802
#endif
2803
    answer.ec = tinyobj_ff::ff_errc::invalid_argument;
2804
    answer.ptr = first;
2805
    return answer;
2806
  }
2807
  if ((*p == UC('-')) ||
2808
      (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
2809
    ++p;
2810
  }
2811
2812
  UC const *const start_num = p;
2813
2814
  while (p != pend && *p == UC('0')) {
2815
    ++p;
2816
  }
2817
2818
  bool const has_leading_zeros = p > start_num;
2819
2820
  UC const *const start_digits = p;
2821
2822
  uint64_t i = 0;
2823
  if (base == 10) {
2824
    loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible
2825
  }
2826
  while (p != pend) {
2827
    uint8_t digit = ch_to_digit(*p);
2828
    if (digit >= base) {
2829
      break;
2830
    }
2831
    i = uint64_t(base) * i + digit; // might overflow, check this later
2832
    p++;
2833
  }
2834
2835
  size_t digit_count = size_t(p - start_digits);
2836
2837
  if (digit_count == 0) {
2838
    if (has_leading_zeros) {
2839
      value = 0;
2840
      answer.ec = tinyobj_ff::ff_errc();
2841
      answer.ptr = p;
2842
    } else {
2843
      answer.ec = tinyobj_ff::ff_errc::invalid_argument;
2844
      answer.ptr = first;
2845
    }
2846
    return answer;
2847
  }
2848
2849
  answer.ptr = p;
2850
2851
  // check u64 overflow
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;
2855
    return answer;
2856
  }
2857
  // this check can be eliminated for all other types, but they will all require
2858
  // a max_digits(base) equivalent
2859
  if (digit_count == max_digits && i < min_safe_u64(base)) {
2860
    answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
2861
    return answer;
2862
  }
2863
2864
  // check other types overflow
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;
2868
      return answer;
2869
    }
2870
  }
2871
2872
  if (negative) {
2873
#ifdef FASTFLOAT_VISUAL_STUDIO
2874
#pragma warning(push)
2875
#pragma warning(disable : 4146)
2876
#endif
2877
    // this weird workaround is required because:
2878
    // - converting unsigned to signed when its value is greater than signed max
2879
    // is UB pre-C++23.
2880
    // - reinterpret_casting (~i + 1) would work, but it is not constexpr
2881
    // this is always optimized into a neg instruction (note: T is an integer
2882
    // type)
2883
    value = T(-std::numeric_limits<T>::max() -
2884
              T(i - uint64_t(std::numeric_limits<T>::max())));
2885
#ifdef FASTFLOAT_VISUAL_STUDIO
2886
#pragma warning(pop)
2887
#endif
2888
  } else {
2889
    value = T(i);
2890
  }
2891
2892
  answer.ec = tinyobj_ff::ff_errc();
2893
  return answer;
2894
}
2895
2896
} // namespace fast_float
2897
2898
#endif
2899
2900
#ifndef FASTFLOAT_FAST_TABLE_H
2901
#define FASTFLOAT_FAST_TABLE_H
2902
2903
namespace fast_float {
2904
2905
/**
2906
 * When mapping numbers from decimal to binary,
2907
 * we go from w * 10^q to m * 2^p but we have
2908
 * 10^q = 5^q * 2^q, so effectively
2909
 * we are trying to match
2910
 * w * 2^q * 5^q to m * 2^p. Thus the powers of two
2911
 * are not a concern since they can be represented
2912
 * exactly using the binary notation, only the powers of five
2913
 * affect the binary significand.
2914
 */
2915
2916
/**
2917
 * The smallest non-zero float (binary64) is 2^-1074.
2918
 * We take as input numbers of the form w x 10^q where w < 2^64.
2919
 * We have that w * 10^-343  <  2^(64-344) 5^-343 < 2^-1076.
2920
 * However, we have that
2921
 * (2^64-1) * 10^-342 =  (2^64-1) * 2^-342 * 5^-342 > 2^-1074.
2922
 * Thus it is possible for a number of the form w * 10^-342 where
2923
 * w is a 64-bit value to be a non-zero floating-point number.
2924
 *********
2925
 * Any number of form w * 10^309 where w>= 1 is going to be
2926
 * infinite in binary64 so we never need to worry about powers
2927
 * of 5 greater than 308.
2928
 */
2929
template <class unused = void> struct powers_template {
2930
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);
2937
  // Powers of five from 5^-342 all the way to 5^308 rounded toward one.
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,
3590
  };
3591
};
3592
3593
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
3594
3595
template <class unused>
3596
constexpr uint64_t
3597
    powers_template<unused>::power_of_five_128[number_of_entries];
3598
3599
#endif
3600
3601
using powers = powers_template<>;
3602
3603
} // namespace fast_float
3604
3605
#endif
3606
3607
#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H
3608
#define FASTFLOAT_DECIMAL_TO_BINARY_H
3609
3610
#include <cmath>
3611
#include <cstdlib>
3612
#include <cstring>
3613
3614
namespace fast_float {
3615
3616
// This will compute or rather approximate w * 5**q and return a pair of 64-bit
3617
// words approximating the result, with the "high" part corresponding to the
3618
// most significant bits and the low part corresponding to the least significant
3619
// bits.
3620
//
3621
template <int bit_precision>
3622
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
3623
25
compute_product_approximation(int64_t q, uint64_t w) {
3624
25
  int const index = 2 * int(q - powers::smallest_power_of_five);
3625
  // For small values of q, e.g., q in [0,27], the answer is always exact
3626
  // because The line value128 firstproduct = full_multiplication(w,
3627
  // power_of_five_128[index]); gives the exact answer.
3628
25
  value128 firstproduct =
3629
25
      full_multiplication(w, powers::power_of_five_128[index]);
3630
25
  static_assert((bit_precision >= 0) && (bit_precision <= 64),
3631
25
                " precision should  be in (0,64]");
3632
25
  constexpr uint64_t precision_mask =
3633
25
      (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
3634
25
                           : uint64_t(0xFFFFFFFFFFFFFFFF);
3635
25
  if ((firstproduct.high & precision_mask) ==
3636
25
      precision_mask) { // could further guard with  (lower + w < lower)
3637
    // regarding the second product, we only need secondproduct.high, but our
3638
    // expectation is that the compiler will optimize this extra work away if
3639
    // needed.
3640
1
    value128 secondproduct =
3641
1
        full_multiplication(w, powers::power_of_five_128[index + 1]);
3642
1
    firstproduct.low += secondproduct.high;
3643
1
    if (secondproduct.high > firstproduct.low) {
3644
1
      firstproduct.high++;
3645
1
    }
3646
1
  }
3647
25
  return firstproduct;
3648
25
}
3649
3650
namespace detail {
3651
/**
3652
 * For q in (0,350), we have that
3653
 *  f = (((152170 + 65536) * q ) >> 16);
3654
 * is equal to
3655
 *   floor(p) + q
3656
 * where
3657
 *   p = log(5**q)/log(2) = q * log(5)/log(2)
3658
 *
3659
 * For negative values of q in (-400,0), we have that
3660
 *  f = (((152170 + 65536) * q ) >> 16);
3661
 * is equal to
3662
 *   -ceil(p) + q
3663
 * where
3664
 *   p = log(5**-q)/log(2) = -q * log(5)/log(2)
3665
 */
3666
25
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept {
3667
25
  return (((152170 + 65536) * q) >> 16) + 63;
3668
25
}
3669
} // namespace detail
3670
3671
// create an adjusted mantissa, biased by the invalid power2
3672
// for significant digits already multiplied by 10 ** q.
3673
template <typename binary>
3674
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa
3675
0
compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept {
3676
0
  int hilz = int(w >> 63) ^ 1;
3677
0
  adjusted_mantissa answer;
3678
0
  answer.mantissa = w << hilz;
3679
0
  int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent();
3680
0
  answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 +
3681
0
                          invalid_am_bias);
3682
0
  return answer;
3683
0
}
3684
3685
// w * 10 ** q, without rounding the representation up.
3686
// the power2 in the exponent will be adjusted by invalid_am_bias.
3687
template <typename binary>
3688
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
3689
0
compute_error(int64_t q, uint64_t w) noexcept {
3690
0
  int lz = leading_zeroes(w);
3691
0
  w <<= lz;
3692
0
  value128 product =
3693
0
      compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
3694
0
  return compute_error_scaled<binary>(q, product.high, lz);
3695
0
}
3696
3697
// Computers w * 10 ** q.
3698
// The returned value should be a valid number that simply needs to be
3699
// packed. However, in some very rare cases, the computation will fail. In such
3700
// cases, we return an adjusted_mantissa with a negative power of 2: the caller
3701
// should recompute in such cases.
3702
template <typename binary>
3703
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
3704
60
compute_float(int64_t q, uint64_t w) noexcept {
3705
60
  adjusted_mantissa answer;
3706
60
  if ((w == 0) || (q < binary::smallest_power_of_ten())) {
3707
24
    answer.power2 = 0;
3708
24
    answer.mantissa = 0;
3709
    // result should be zero
3710
24
    return answer;
3711
24
  }
3712
36
  if (q > binary::largest_power_of_ten()) {
3713
    // we want to get infinity:
3714
11
    answer.power2 = binary::infinite_power();
3715
11
    answer.mantissa = 0;
3716
11
    return answer;
3717
11
  }
3718
  // At this point in time q is in [powers::smallest_power_of_five,
3719
  // powers::largest_power_of_five].
3720
3721
  // We want the most significant bit of i to be 1. Shift if needed.
3722
25
  int lz = leading_zeroes(w);
3723
25
  w <<= lz;
3724
3725
  // The required precision is binary::mantissa_explicit_bits() + 3 because
3726
  // 1. We need the implicit bit
3727
  // 2. We need an extra bit for rounding purposes
3728
  // 3. We might lose a bit due to the "upperbit" routine (result too small,
3729
  // requiring a shift)
3730
3731
25
  value128 product =
3732
25
      compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
3733
  // The computed 'product' is always sufficient.
3734
  // Mathematical proof:
3735
  // Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to
3736
  // appear) See script/mushtak_lemire.py
3737
3738
  // The "compute_product_approximation" function can be slightly slower than a
3739
  // branchless approach: value128 product = compute_product(q, w); but in
3740
  // practice, we can win big with the compute_product_approximation if its
3741
  // additional branch is easily predicted. Which is best is data specific.
3742
25
  int upperbit = int(product.high >> 63);
3743
25
  int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3;
3744
3745
25
  answer.mantissa = product.high >> shift;
3746
3747
25
  answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz -
3748
25
                          binary::minimum_exponent());
3749
25
  if (answer.power2 <= 0) { // we have a subnormal?
3750
    // Here have that answer.power2 <= 0 so -answer.power2 >= 0
3751
0
    if (-answer.power2 + 1 >=
3752
0
        64) { // if we have more than 64 bits below the minimum exponent, you
3753
              // have a zero for sure.
3754
0
      answer.power2 = 0;
3755
0
      answer.mantissa = 0;
3756
      // result should be zero
3757
0
      return answer;
3758
0
    }
3759
    // next line is safe because -answer.power2 + 1 < 64
3760
0
    answer.mantissa >>= -answer.power2 + 1;
3761
    // Thankfully, we can't have both "round-to-even" and subnormals because
3762
    // "round-to-even" only occurs for powers close to 0 in the 32-bit and
3763
    // and 64-bit case (with no more than 19 digits).
3764
0
    answer.mantissa += (answer.mantissa & 1); // round up
3765
0
    answer.mantissa >>= 1;
3766
    // There is a weird scenario where we don't have a subnormal but just.
3767
    // Suppose we start with 2.2250738585072013e-308, we end up
3768
    // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal
3769
    // whereas 0x40000000000000 x 2^-1023-53  is normal. Now, we need to round
3770
    // up 0x3fffffffffffff x 2^-1023-53  and once we do, we are no longer
3771
    // subnormal, but we can only know this after rounding.
3772
    // So we only declare a subnormal if we are smaller than the threshold.
3773
0
    answer.power2 =
3774
0
        (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits()))
3775
0
            ? 0
3776
0
            : 1;
3777
0
    return answer;
3778
0
  }
3779
3780
  // usually, we round *up*, but if we fall right in between and and we have an
3781
  // even basis, we need to round down
3782
  // We are only concerned with the cases where 5**q fits in single 64-bit word.
3783
25
  if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) &&
3784
0
      (q <= binary::max_exponent_round_to_even()) &&
3785
0
      ((answer.mantissa & 3) == 1)) { // we may fall between two floats!
3786
    // To be in-between two floats we need that in doing
3787
    //   answer.mantissa = product.high >> (upperbit + 64 -
3788
    //   binary::mantissa_explicit_bits() - 3);
3789
    // ... we dropped out only zeroes. But if this happened, then we can go
3790
    // back!!!
3791
0
    if ((answer.mantissa << shift) == product.high) {
3792
0
      answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up
3793
0
    }
3794
0
  }
3795
3796
25
  answer.mantissa += (answer.mantissa & 1); // round up
3797
25
  answer.mantissa >>= 1;
3798
25
  if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {
3799
1
    answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());
3800
1
    answer.power2++; // undo previous addition
3801
1
  }
3802
3803
25
  answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());
3804
25
  if (answer.power2 >= binary::infinite_power()) { // infinity
3805
0
    answer.power2 = binary::infinite_power();
3806
0
    answer.mantissa = 0;
3807
0
  }
3808
25
  return answer;
3809
25
}
3810
3811
} // namespace fast_float
3812
3813
#endif
3814
3815
#ifndef FASTFLOAT_BIGINT_H
3816
#define FASTFLOAT_BIGINT_H
3817
3818
#include <cstring>
3819
3820
3821
namespace fast_float {
3822
3823
// the limb width: we want efficient multiplication of double the bits in
3824
// limb, or for 64-bit limbs, at least 64-bit multiplication where we can
3825
// extract the high and low parts efficiently. this is every 64-bit
3826
// architecture except for sparc, which emulates 128-bit multiplication.
3827
// we might have platforms where `CHAR_BIT` is not 8, so let's avoid
3828
// doing `8 * sizeof(limb)`.
3829
#if defined(FASTFLOAT_64BIT) && !defined(__sparc)
3830
#define FASTFLOAT_64BIT_LIMB 1
3831
typedef uint64_t limb;
3832
constexpr size_t limb_bits = 64;
3833
#else
3834
#define FASTFLOAT_32BIT_LIMB
3835
typedef uint32_t limb;
3836
constexpr size_t limb_bits = 32;
3837
#endif
3838
3839
typedef span<limb> limb_span;
3840
3841
// number of bits in a bigint. this needs to be at least the number
3842
// of bits required to store the largest bigint, which is
3843
// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or
3844
// ~3600 bits, so we round to 4000.
3845
constexpr size_t bigint_bits = 4000;
3846
constexpr size_t bigint_limbs = bigint_bits / limb_bits;
3847
3848
// vector-like type that is allocated on the stack. the entire
3849
// buffer is pre-allocated, and only the length changes.
3850
template <uint16_t size> struct stackvec {
3851
  limb data[size];
3852
  // we never need more than 150 limbs
3853
  uint16_t length{0};
3854
3855
0
  stackvec() = default;
3856
  stackvec(stackvec const &) = delete;
3857
  stackvec &operator=(stackvec const &) = delete;
3858
  stackvec(stackvec &&) = delete;
3859
  stackvec &operator=(stackvec &&other) = delete;
3860
3861
  // create stack vector from existing limb span.
3862
0
  FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
3863
0
    FASTFLOAT_ASSERT(try_extend(s));
3864
0
  }
3865
3866
0
  FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept {
3867
0
    FASTFLOAT_DEBUG_ASSERT(index < length);
3868
0
    return data[index];
3869
0
  }
3870
3871
0
  FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept {
3872
0
    FASTFLOAT_DEBUG_ASSERT(index < length);
3873
0
    return data[index];
3874
0
  }
3875
3876
  // index from the end of the container
3877
0
  FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept {
3878
0
    FASTFLOAT_DEBUG_ASSERT(index < length);
3879
0
    size_t rindex = length - index - 1;
3880
0
    return data[rindex];
3881
0
  }
3882
3883
  // set the length, without bounds checking.
3884
0
  FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
3885
0
    length = uint16_t(len);
3886
0
  }
3887
3888
0
  constexpr size_t len() const noexcept { return length; }
3889
3890
0
  constexpr bool is_empty() const noexcept { return length == 0; }
3891
3892
0
  constexpr size_t capacity() const noexcept { return size; }
3893
3894
  // append item to vector, without bounds checking
3895
0
  FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
3896
0
    data[length] = value;
3897
0
    length++;
3898
0
  }
3899
3900
  // append item to vector, returning if item was added
3901
0
  FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
3902
0
    if (len() < capacity()) {
3903
0
      push_unchecked(value);
3904
0
      return true;
3905
0
    } else {
3906
0
      return false;
3907
0
    }
3908
0
  }
3909
3910
  // add items to the vector, from a span, without bounds checking
3911
0
  FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
3912
0
    limb *ptr = data + length;
3913
0
    tinyobj_ff::copy_n(s.ptr, s.len(), ptr);
3914
0
    set_len(len() + s.len());
3915
0
  }
3916
3917
  // try to add items to the vector, returning if items were added
3918
0
  FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
3919
0
    if (len() + s.len() <= capacity()) {
3920
0
      extend_unchecked(s);
3921
0
      return true;
3922
0
    } else {
3923
0
      return false;
3924
0
    }
3925
0
  }
3926
3927
  // resize the vector, without bounds checking
3928
  // if the new size is longer than the vector, assign value to each
3929
  // appended item.
3930
  FASTFLOAT_CONSTEXPR20
3931
0
  void resize_unchecked(size_t new_len, limb value) noexcept {
3932
0
    if (new_len > len()) {
3933
0
      size_t count = new_len - len();
3934
0
      limb *first = data + len();
3935
0
      limb *last = first + count;
3936
0
      tinyobj_ff::fill(first, last, value);
3937
0
      set_len(new_len);
3938
0
    } else {
3939
0
      set_len(new_len);
3940
0
    }
3941
0
  }
3942
3943
  // try to resize the vector, returning if the vector was resized.
3944
0
  FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
3945
0
    if (new_len > capacity()) {
3946
0
      return false;
3947
0
    } else {
3948
0
      resize_unchecked(new_len, value);
3949
0
      return true;
3950
0
    }
3951
0
  }
3952
3953
  // check if any limbs are non-zero after the given index.
3954
  // this needs to be done in reverse order, since the index
3955
  // is relative to the most significant limbs.
3956
0
  FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept {
3957
0
    while (index < len()) {
3958
0
      if (rindex(index) != 0) {
3959
0
        return true;
3960
0
      }
3961
0
      index++;
3962
0
    }
3963
0
    return false;
3964
0
  }
3965
3966
  // normalize the big integer, so most-significant zero limbs are removed.
3967
0
  FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
3968
0
    while (len() > 0 && rindex(0) == 0) {
3969
0
      length--;
3970
0
    }
3971
0
  }
3972
};
3973
3974
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
3975
0
empty_hi64(bool &truncated) noexcept {
3976
0
  truncated = false;
3977
0
  return 0;
3978
0
}
3979
3980
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
3981
0
uint64_hi64(uint64_t r0, bool &truncated) noexcept {
3982
0
  truncated = false;
3983
0
  int shl = leading_zeroes(r0);
3984
0
  return r0 << shl;
3985
0
}
3986
3987
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
3988
0
uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept {
3989
0
  int shl = leading_zeroes(r0);
3990
0
  if (shl == 0) {
3991
0
    truncated = r1 != 0;
3992
0
    return r0;
3993
0
  } else {
3994
0
    int shr = 64 - shl;
3995
0
    truncated = (r1 << shl) != 0;
3996
0
    return (r0 << shl) | (r1 >> shr);
3997
0
  }
3998
0
}
3999
4000
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4001
0
uint32_hi64(uint32_t r0, bool &truncated) noexcept {
4002
0
  return uint64_hi64(r0, truncated);
4003
0
}
4004
4005
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4006
0
uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept {
4007
0
  uint64_t x0 = r0;
4008
0
  uint64_t x1 = r1;
4009
0
  return uint64_hi64((x0 << 32) | x1, truncated);
4010
0
}
4011
4012
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
4013
0
uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept {
4014
0
  uint64_t x0 = r0;
4015
0
  uint64_t x1 = r1;
4016
0
  uint64_t x2 = r2;
4017
0
  return uint64_hi64(x0, (x1 << 32) | x2, truncated);
4018
0
}
4019
4020
// add two small integers, checking for overflow.
4021
// we want an efficient operation. for msvc, where
4022
// we don't have built-in intrinsics, this is still
4023
// pretty fast.
4024
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
4025
0
scalar_add(limb x, limb y, bool &overflow) noexcept {
4026
0
  limb z;
4027
// gcc and clang
4028
0
#if defined(__has_builtin)
4029
0
#if __has_builtin(__builtin_add_overflow)
4030
0
  if (!cpp20_and_in_constexpr()) {
4031
0
    overflow = __builtin_add_overflow(x, y, &z);
4032
0
    return z;
4033
0
  }
4034
0
#endif
4035
0
#endif
4036
4037
  // generic, this still optimizes correctly on MSVC.
4038
0
  z = x + y;
4039
0
  overflow = z < x;
4040
0
  return z;
4041
0
}
4042
4043
// multiply two small integers, getting both the high and low bits.
4044
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
4045
0
scalar_mul(limb x, limb y, limb &carry) noexcept {
4046
0
#ifdef FASTFLOAT_64BIT_LIMB
4047
0
#if defined(__SIZEOF_INT128__)
4048
  // GCC and clang both define it as an extension.
4049
0
  __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
4050
0
  carry = limb(z >> limb_bits);
4051
0
  return limb(z);
4052
#else
4053
  // fallback, no native 128-bit integer multiplication with carry.
4054
  // on msvc, this optimizes identically, somehow.
4055
  value128 z = full_multiplication(x, y);
4056
  bool overflow;
4057
  z.low = scalar_add(z.low, carry, overflow);
4058
  z.high += uint64_t(overflow); // cannot overflow
4059
  carry = z.high;
4060
  return z.low;
4061
#endif
4062
#else
4063
  uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
4064
  carry = limb(z >> limb_bits);
4065
  return limb(z);
4066
#endif
4067
0
}
4068
4069
// add scalar value to bigint starting from offset.
4070
// used in grade school multiplication
4071
template <uint16_t size>
4072
inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec<size> &vec, limb y,
4073
0
                                                 size_t start) noexcept {
4074
0
  size_t index = start;
4075
0
  limb carry = y;
4076
0
  bool overflow;
4077
0
  while (carry != 0 && index < vec.len()) {
4078
0
    vec[index] = scalar_add(vec[index], carry, overflow);
4079
0
    carry = limb(overflow);
4080
0
    index += 1;
4081
0
  }
4082
0
  if (carry != 0) {
4083
0
    FASTFLOAT_TRY(vec.try_push(carry));
4084
0
  }
4085
0
  return true;
4086
0
}
4087
4088
// add scalar value to bigint.
4089
template <uint16_t size>
4090
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
4091
0
small_add(stackvec<size> &vec, limb y) noexcept {
4092
0
  return small_add_from(vec, y, 0);
4093
0
}
4094
4095
// multiply bigint by scalar value.
4096
template <uint16_t size>
4097
inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec<size> &vec,
4098
0
                                            limb y) noexcept {
4099
0
  limb carry = 0;
4100
0
  for (size_t index = 0; index < vec.len(); index++) {
4101
0
    vec[index] = scalar_mul(vec[index], y, carry);
4102
0
  }
4103
0
  if (carry != 0) {
4104
0
    FASTFLOAT_TRY(vec.try_push(carry));
4105
0
  }
4106
0
  return true;
4107
0
}
4108
4109
// add bigint to bigint starting from index.
4110
// used in grade school multiplication
4111
template <uint16_t size>
4112
FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec<size> &x, limb_span y,
4113
0
                                          size_t start) noexcept {
4114
  // the effective x buffer is from `xstart..x.len()`, so exit early
4115
  // if we can't get that current range.
4116
0
  if (x.len() < start || y.len() > x.len() - start) {
4117
0
    FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
4118
0
  }
4119
4120
0
  bool carry = false;
4121
0
  for (size_t index = 0; index < y.len(); index++) {
4122
0
    limb xi = x[index + start];
4123
0
    limb yi = y[index];
4124
0
    bool c1 = false;
4125
0
    bool c2 = false;
4126
0
    xi = scalar_add(xi, yi, c1);
4127
0
    if (carry) {
4128
0
      xi = scalar_add(xi, 1, c2);
4129
0
    }
4130
0
    x[index + start] = xi;
4131
0
    carry = c1 | c2;
4132
0
  }
4133
4134
  // handle overflow
4135
0
  if (carry) {
4136
0
    FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
4137
0
  }
4138
0
  return true;
4139
0
}
4140
4141
// add bigint to bigint.
4142
template <uint16_t size>
4143
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
4144
large_add_from(stackvec<size> &x, limb_span y) noexcept {
4145
  return large_add_from(x, y, 0);
4146
}
4147
4148
// grade-school multiplication algorithm
4149
template <uint16_t size>
4150
0
FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec<size> &x, limb_span y) noexcept {
4151
0
  limb_span xs = limb_span(x.data, x.len());
4152
0
  stackvec<size> z(xs);
4153
0
  limb_span zs = limb_span(z.data, z.len());
4154
4155
0
  if (y.len() != 0) {
4156
0
    limb y0 = y[0];
4157
0
    FASTFLOAT_TRY(small_mul(x, y0));
4158
0
    for (size_t index = 1; index < y.len(); index++) {
4159
0
      limb yi = y[index];
4160
0
      stackvec<size> zi;
4161
0
      if (yi != 0) {
4162
        // re-use the same buffer throughout
4163
0
        zi.set_len(0);
4164
0
        FASTFLOAT_TRY(zi.try_extend(zs));
4165
0
        FASTFLOAT_TRY(small_mul(zi, yi));
4166
0
        limb_span zis = limb_span(zi.data, zi.len());
4167
0
        FASTFLOAT_TRY(large_add_from(x, zis, index));
4168
0
      }
4169
0
    }
4170
0
  }
4171
4172
0
  x.normalize();
4173
0
  return true;
4174
0
}
4175
4176
// grade-school multiplication algorithm
4177
template <uint16_t size>
4178
0
FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec<size> &x, limb_span y) noexcept {
4179
0
  if (y.len() == 1) {
4180
0
    FASTFLOAT_TRY(small_mul(x, y[0]));
4181
0
  } else {
4182
0
    FASTFLOAT_TRY(long_mul(x, y));
4183
0
  }
4184
0
  return true;
4185
0
}
4186
4187
template <typename = void> struct pow5_tables {
4188
  static constexpr uint32_t large_step = 135;
4189
  static constexpr uint64_t small_power_of_5[] = {
4190
      1UL,
4191
      5UL,
4192
      25UL,
4193
      125UL,
4194
      625UL,
4195
      3125UL,
4196
      15625UL,
4197
      78125UL,
4198
      390625UL,
4199
      1953125UL,
4200
      9765625UL,
4201
      48828125UL,
4202
      244140625UL,
4203
      1220703125UL,
4204
      6103515625UL,
4205
      30517578125UL,
4206
      152587890625UL,
4207
      762939453125UL,
4208
      3814697265625UL,
4209
      19073486328125UL,
4210
      95367431640625UL,
4211
      476837158203125UL,
4212
      2384185791015625UL,
4213
      11920928955078125UL,
4214
      59604644775390625UL,
4215
      298023223876953125UL,
4216
      1490116119384765625UL,
4217
      7450580596923828125UL,
4218
  };
4219
#ifdef FASTFLOAT_64BIT_LIMB
4220
  constexpr static limb large_power_of_5[] = {
4221
      1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
4222
      10482974169319127550UL, 198276706040285095UL};
4223
#else
4224
  constexpr static limb large_power_of_5[] = {
4225
      4279965485U, 329373468U,  4020270615U, 2137533757U, 4287402176U,
4226
      1057042919U, 1071430142U, 2440757623U, 381945767U,  46164893U};
4227
#endif
4228
};
4229
4230
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
4231
4232
template <typename T> constexpr uint32_t pow5_tables<T>::large_step;
4233
4234
template <typename T> constexpr uint64_t pow5_tables<T>::small_power_of_5[];
4235
4236
template <typename T> constexpr limb pow5_tables<T>::large_power_of_5[];
4237
4238
#endif
4239
4240
// big integer type. implements a small subset of big integer
4241
// arithmetic, using simple algorithms since asymptotically
4242
// faster algorithms are slower for a small number of limbs.
4243
// all operations assume the big-integer is normalized.
4244
struct bigint : pow5_tables<> {
4245
  // storage of the limbs, in little-endian order.
4246
  stackvec<bigint_limbs> vec;
4247
4248
0
  FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
4249
4250
  bigint(bigint const &) = delete;
4251
  bigint &operator=(bigint const &) = delete;
4252
  bigint(bigint &&) = delete;
4253
  bigint &operator=(bigint &&other) = delete;
4254
4255
0
  FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() {
4256
0
#ifdef FASTFLOAT_64BIT_LIMB
4257
0
    vec.push_unchecked(value);
4258
#else
4259
    vec.push_unchecked(uint32_t(value));
4260
    vec.push_unchecked(uint32_t(value >> 32));
4261
#endif
4262
0
    vec.normalize();
4263
0
  }
4264
4265
  // get the high 64 bits from the vector, and if bits were truncated.
4266
  // this is to get the significant digits for the float.
4267
0
  FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept {
4268
0
#ifdef FASTFLOAT_64BIT_LIMB
4269
0
    if (vec.len() == 0) {
4270
0
      return empty_hi64(truncated);
4271
0
    } else if (vec.len() == 1) {
4272
0
      return uint64_hi64(vec.rindex(0), truncated);
4273
0
    } else {
4274
0
      uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
4275
0
      truncated |= vec.nonzero(2);
4276
0
      return result;
4277
0
    }
4278
#else
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);
4285
    } else {
4286
      uint64_t result =
4287
          uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
4288
      truncated |= vec.nonzero(3);
4289
      return result;
4290
    }
4291
#endif
4292
0
  }
4293
4294
  // compare two big integers, returning the large value.
4295
  // assumes both are normalized. if the return value is
4296
  // negative, other is larger, if the return value is
4297
  // positive, this is larger, otherwise they are equal.
4298
  // the limbs are stored in little-endian order, so we
4299
  // must compare the limbs in ever order.
4300
0
  FASTFLOAT_CONSTEXPR20 int compare(bigint const &other) const noexcept {
4301
0
    if (vec.len() > other.vec.len()) {
4302
0
      return 1;
4303
0
    } else if (vec.len() < other.vec.len()) {
4304
0
      return -1;
4305
0
    } else {
4306
0
      for (size_t index = vec.len(); index > 0; index--) {
4307
0
        limb xi = vec[index - 1];
4308
0
        limb yi = other.vec[index - 1];
4309
0
        if (xi > yi) {
4310
0
          return 1;
4311
0
        } else if (xi < yi) {
4312
0
          return -1;
4313
0
        }
4314
0
      }
4315
0
      return 0;
4316
0
    }
4317
0
  }
4318
4319
  // shift left each limb n bits, carrying over to the new limb
4320
  // returns true if we were able to shift all the digits.
4321
0
  FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept {
4322
    // Internally, for each item, we shift left by n, and add the previous
4323
    // right shifted limb-bits.
4324
    // For example, we transform (for u8) shifted left 2, to:
4325
    //      b10100100 b01000010
4326
    //      b10 b10010001 b00001000
4327
0
    FASTFLOAT_DEBUG_ASSERT(n != 0);
4328
0
    FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);
4329
4330
0
    size_t shl = n;
4331
0
    size_t shr = limb_bits - shl;
4332
0
    limb prev = 0;
4333
0
    for (size_t index = 0; index < vec.len(); index++) {
4334
0
      limb xi = vec[index];
4335
0
      vec[index] = (xi << shl) | (prev >> shr);
4336
0
      prev = xi;
4337
0
    }
4338
4339
0
    limb carry = prev >> shr;
4340
0
    if (carry != 0) {
4341
0
      return vec.try_push(carry);
4342
0
    }
4343
0
    return true;
4344
0
  }
4345
4346
  // move the limbs left by `n` limbs.
4347
0
  FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept {
4348
0
    FASTFLOAT_DEBUG_ASSERT(n != 0);
4349
0
    if (n + vec.len() > vec.capacity()) {
4350
0
      return false;
4351
0
    } else if (!vec.is_empty()) {
4352
      // move limbs
4353
0
      limb *dst = vec.data + n;
4354
0
      limb const *src = vec.data;
4355
0
      tinyobj_ff::copy_backward(src, src + vec.len(), dst + vec.len());
4356
      // fill in empty limbs
4357
0
      limb *first = vec.data;
4358
0
      limb *last = first + n;
4359
0
      tinyobj_ff::fill(first, last, 0);
4360
0
      vec.set_len(n + vec.len());
4361
0
      return true;
4362
0
    } else {
4363
0
      return true;
4364
0
    }
4365
0
  }
4366
4367
  // move the limbs left by `n` bits.
4368
0
  FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
4369
0
    size_t rem = n % limb_bits;
4370
0
    size_t div = n / limb_bits;
4371
0
    if (rem != 0) {
4372
0
      FASTFLOAT_TRY(shl_bits(rem));
4373
0
    }
4374
0
    if (div != 0) {
4375
0
      FASTFLOAT_TRY(shl_limbs(div));
4376
0
    }
4377
0
    return true;
4378
0
  }
4379
4380
  // get the number of leading zeros in the bigint.
4381
0
  FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept {
4382
0
    if (vec.is_empty()) {
4383
0
      return 0;
4384
0
    } else {
4385
0
#ifdef FASTFLOAT_64BIT_LIMB
4386
0
      return leading_zeroes(vec.rindex(0));
4387
#else
4388
      // no use defining a specialized leading_zeroes for a 32-bit type.
4389
      uint64_t r0 = vec.rindex(0);
4390
      return leading_zeroes(r0 << 32);
4391
#endif
4392
0
    }
4393
0
  }
4394
4395
  // get the number of bits in the bigint.
4396
0
  FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept {
4397
0
    int lz = ctlz();
4398
0
    return int(limb_bits * vec.len()) - lz;
4399
0
  }
4400
4401
0
  FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); }
4402
4403
0
  FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); }
4404
4405
  // multiply as if by 2 raised to a power.
4406
0
  FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); }
4407
4408
  // multiply as if by 5 raised to a power.
4409
0
  FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
4410
    // multiply by a power of 5
4411
0
    size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
4412
0
    limb_span large = limb_span(large_power_of_5, large_length);
4413
0
    while (exp >= large_step) {
4414
0
      FASTFLOAT_TRY(large_mul(vec, large));
4415
0
      exp -= large_step;
4416
0
    }
4417
0
#ifdef FASTFLOAT_64BIT_LIMB
4418
0
    uint32_t small_step = 27;
4419
0
    limb max_native = 7450580596923828125UL;
4420
#else
4421
    uint32_t small_step = 13;
4422
    limb max_native = 1220703125U;
4423
#endif
4424
0
    while (exp >= small_step) {
4425
0
      FASTFLOAT_TRY(small_mul(vec, max_native));
4426
0
      exp -= small_step;
4427
0
    }
4428
0
    if (exp != 0) {
4429
      // Work around clang bug https://godbolt.org/z/zedh7rrhc
4430
      // This is similar to https://github.com/llvm/llvm-project/issues/47746,
4431
      // except the workaround described there don't work here
4432
0
      FASTFLOAT_TRY(small_mul(
4433
0
          vec, limb(((void)small_power_of_5[0], small_power_of_5[exp]))));
4434
0
    }
4435
4436
0
    return true;
4437
0
  }
4438
4439
  // multiply as if by 10 raised to a power.
4440
0
  FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept {
4441
0
    FASTFLOAT_TRY(pow5(exp));
4442
0
    return pow2(exp);
4443
0
  }
4444
};
4445
4446
} // namespace fast_float
4447
4448
#endif
4449
4450
#ifndef FASTFLOAT_DIGIT_COMPARISON_H
4451
#define FASTFLOAT_DIGIT_COMPARISON_H
4452
4453
#include <cstring>
4454
4455
4456
namespace fast_float {
4457
4458
// 1e0 to 1e19
4459
constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
4460
                                                    10UL,
4461
                                                    100UL,
4462
                                                    1000UL,
4463
                                                    10000UL,
4464
                                                    100000UL,
4465
                                                    1000000UL,
4466
                                                    10000000UL,
4467
                                                    100000000UL,
4468
                                                    1000000000UL,
4469
                                                    10000000000UL,
4470
                                                    100000000000UL,
4471
                                                    1000000000000UL,
4472
                                                    10000000000000UL,
4473
                                                    100000000000000UL,
4474
                                                    1000000000000000UL,
4475
                                                    10000000000000000UL,
4476
                                                    100000000000000000UL,
4477
                                                    1000000000000000000UL,
4478
                                                    10000000000000000000UL};
4479
4480
// calculate the exponent, in scientific notation, of the number.
4481
// this algorithm is not even close to optimized, but it has no practical
4482
// effect on performance: in order to have a faster algorithm, we'd need
4483
// to slow down performance for faster algorithms, and this is still fast.
4484
template <typename UC>
4485
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
4486
0
scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
4487
0
  uint64_t mantissa = num.mantissa;
4488
0
  int32_t exponent = int32_t(num.exponent);
4489
0
  while (mantissa >= 10000) {
4490
0
    mantissa /= 10000;
4491
0
    exponent += 4;
4492
0
  }
4493
0
  while (mantissa >= 100) {
4494
0
    mantissa /= 100;
4495
0
    exponent += 2;
4496
0
  }
4497
0
  while (mantissa >= 10) {
4498
0
    mantissa /= 10;
4499
0
    exponent += 1;
4500
0
  }
4501
0
  return exponent;
4502
0
}
4503
4504
// this converts a native floating-point number to an extended-precision float.
4505
template <typename T>
4506
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4507
0
to_extended(T value) noexcept {
4508
0
  using equiv_uint = equiv_uint_t<T>;
4509
0
  constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
4510
0
  constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
4511
0
  constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
4512
4513
0
  adjusted_mantissa am;
4514
0
  int32_t bias = binary_format<T>::mantissa_explicit_bits() -
4515
0
                 binary_format<T>::minimum_exponent();
4516
0
  equiv_uint bits;
4517
#if FASTFLOAT_HAS_BIT_CAST
4518
  bits = std::bit_cast<equiv_uint>(value);
4519
#else
4520
0
  ::memcpy(&bits, &value, sizeof(T));
4521
0
#endif
4522
0
  if ((bits & exponent_mask) == 0) {
4523
    // denormal
4524
0
    am.power2 = 1 - bias;
4525
0
    am.mantissa = bits & mantissa_mask;
4526
0
  } else {
4527
    // normal
4528
0
    am.power2 = int32_t((bits & exponent_mask) >>
4529
0
                        binary_format<T>::mantissa_explicit_bits());
4530
0
    am.power2 -= bias;
4531
0
    am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
4532
0
  }
4533
4534
0
  return am;
4535
0
}
4536
4537
// get the extended precision value of the halfway point between b and b+u.
4538
// we are given a native float that represents b, so we need to adjust it
4539
// halfway between b and b+u.
4540
template <typename T>
4541
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4542
0
to_extended_halfway(T value) noexcept {
4543
0
  adjusted_mantissa am = to_extended(value);
4544
0
  am.mantissa <<= 1;
4545
0
  am.mantissa += 1;
4546
0
  am.power2 -= 1;
4547
0
  return am;
4548
0
}
4549
4550
// round an extended-precision float to the nearest machine float.
4551
template <typename T, typename callback>
4552
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am,
4553
0
                                                         callback cb) noexcept {
4554
0
  int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
4555
0
  if (-am.power2 >= mantissa_shift) {
4556
    // have a denormal float
4557
0
    int32_t shift = -am.power2 + 1;
4558
0
    cb(am, tinyobj_ff::min_val<int32_t>(shift, 64));
4559
    // check for round-up: if rounding-nearest carried us to the hidden bit.
4560
0
    am.power2 = (am.mantissa <
4561
0
                 (uint64_t(1) << binary_format<T>::mantissa_explicit_bits()))
4562
0
                    ? 0
4563
0
                    : 1;
4564
0
    return;
4565
0
  }
4566
4567
  // have a normal float, use the default shift.
4568
0
  cb(am, mantissa_shift);
4569
4570
  // check for carry
4571
0
  if (am.mantissa >=
4572
0
      (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
4573
0
    am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
4574
0
    am.power2++;
4575
0
  }
4576
4577
  // check for infinite: we could have carried to an infinite power
4578
0
  am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
4579
0
  if (am.power2 >= binary_format<T>::infinite_power()) {
4580
0
    am.power2 = binary_format<T>::infinite_power();
4581
0
    am.mantissa = 0;
4582
0
  }
4583
0
}
Unexecuted instantiation: void fast_float::round<double, fast_float::positive_digit_comp<double>(fast_float::bigint&, int)::{lambda(fast_float::adjusted_mantissa&, int)#1}>(fast_float::adjusted_mantissa&, fast_float::positive_digit_comp<double>(fast_float::bigint&, int)::{lambda(fast_float::adjusted_mantissa&, int)#1})
Unexecuted instantiation: void fast_float::round<double, fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#1}>(fast_float::adjusted_mantissa&, fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#1})
Unexecuted instantiation: void fast_float::round<double, fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#2}>(fast_float::adjusted_mantissa&, fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#2})
4584
4585
template <typename callback>
4586
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
4587
round_nearest_tie_even(adjusted_mantissa &am, int32_t shift,
4588
0
                       callback cb) noexcept {
4589
0
  uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1;
4590
0
  uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1);
4591
0
  uint64_t truncated_bits = am.mantissa & mask;
4592
0
  bool is_above = truncated_bits > halfway;
4593
0
  bool is_halfway = truncated_bits == halfway;
4594
4595
  // shift digits into position
4596
0
  if (shift == 64) {
4597
0
    am.mantissa = 0;
4598
0
  } else {
4599
0
    am.mantissa >>= shift;
4600
0
  }
4601
0
  am.power2 += shift;
4602
4603
0
  bool is_odd = (am.mantissa & 1) == 1;
4604
0
  am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
4605
0
}
Unexecuted instantiation: void fast_float::round_nearest_tie_even<fast_float::positive_digit_comp<double>(fast_float::bigint&, int)::{lambda(fast_float::adjusted_mantissa&, int)#1}::operator()(fast_float::adjusted_mantissa&, int) const::{lambda(bool, bool, bool)#1}>(fast_float::adjusted_mantissa&, int, fast_float::positive_digit_comp<double>(fast_float::bigint&, int)::{lambda(fast_float::adjusted_mantissa&, int)#1}::operator()(fast_float::adjusted_mantissa&, int) const::{lambda(bool, bool, bool)#1})
Unexecuted instantiation: void fast_float::round_nearest_tie_even<fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#2}::operator()(fast_float::adjusted_mantissa&, int) const::{lambda(bool, bool, bool)#1}>(fast_float::adjusted_mantissa&, int, fast_float::negative_digit_comp<double>(fast_float::bigint&, fast_float::adjusted_mantissa, int)::{lambda(fast_float::adjusted_mantissa&, int)#2}::operator()(fast_float::adjusted_mantissa&, int) const::{lambda(bool, bool, bool)#1})
4606
4607
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
4608
0
round_down(adjusted_mantissa &am, int32_t shift) noexcept {
4609
0
  if (shift == 64) {
4610
0
    am.mantissa = 0;
4611
0
  } else {
4612
0
    am.mantissa >>= shift;
4613
0
  }
4614
0
  am.power2 += shift;
4615
0
}
4616
4617
template <typename UC>
4618
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
4619
0
skip_zeros(UC const *&first, UC const *last) noexcept {
4620
0
  uint64_t val;
4621
0
  while (!cpp20_and_in_constexpr() &&
4622
0
         tinyobj_ff::distance(first, last) >= int_cmp_len<UC>()) {
4623
0
    ::memcpy(&val, first, sizeof(uint64_t));
4624
0
    if (val != int_cmp_zeros<UC>()) {
4625
0
      break;
4626
0
    }
4627
0
    first += int_cmp_len<UC>();
4628
0
  }
4629
0
  while (first != last) {
4630
0
    if (*first != UC('0')) {
4631
0
      break;
4632
0
    }
4633
0
    first++;
4634
0
  }
4635
0
}
4636
4637
// determine if any non-zero digits were truncated.
4638
// all characters must be valid digits.
4639
template <typename UC>
4640
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
4641
0
is_truncated(UC const *first, UC const *last) noexcept {
4642
  // do 8-bit optimizations, can just compare to 8 literal 0s.
4643
0
  uint64_t val;
4644
0
  while (!cpp20_and_in_constexpr() &&
4645
0
         tinyobj_ff::distance(first, last) >= int_cmp_len<UC>()) {
4646
0
    ::memcpy(&val, first, sizeof(uint64_t));
4647
0
    if (val != int_cmp_zeros<UC>()) {
4648
0
      return true;
4649
0
    }
4650
0
    first += int_cmp_len<UC>();
4651
0
  }
4652
0
  while (first != last) {
4653
0
    if (*first != UC('0')) {
4654
0
      return true;
4655
0
    }
4656
0
    ++first;
4657
0
  }
4658
0
  return false;
4659
0
}
4660
4661
template <typename UC>
4662
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
4663
0
is_truncated(span<UC const> s) noexcept {
4664
0
  return is_truncated(s.ptr, s.ptr + s.len());
4665
0
}
4666
4667
template <typename UC>
4668
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
4669
parse_eight_digits(UC const *&p, limb &value, size_t &counter,
4670
0
                   size_t &count) noexcept {
4671
0
  value = value * 100000000 + parse_eight_digits_unrolled(p);
4672
0
  p += 8;
4673
0
  counter += 8;
4674
0
  count += 8;
4675
0
}
4676
4677
template <typename UC>
4678
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
4679
parse_one_digit(UC const *&p, limb &value, size_t &counter,
4680
0
                size_t &count) noexcept {
4681
0
  value = value * 10 + limb(*p - UC('0'));
4682
0
  p++;
4683
0
  counter++;
4684
0
  count++;
4685
0
}
4686
4687
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
4688
0
add_native(bigint &big, limb power, limb value) noexcept {
4689
0
  big.mul(power);
4690
0
  big.add(value);
4691
0
}
4692
4693
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
4694
0
round_up_bigint(bigint &big, size_t &count) noexcept {
4695
  // need to round-up the digits, but need to avoid rounding
4696
  // ....9999 to ...10000, which could cause a false halfway point.
4697
0
  add_native(big, 10, 1);
4698
0
  count++;
4699
0
}
4700
4701
// parse the significant digits into a big integer
4702
template <typename UC>
4703
inline FASTFLOAT_CONSTEXPR20 void
4704
parse_mantissa(bigint &result, parsed_number_string_t<UC> &num,
4705
0
               size_t max_digits, size_t &digits) noexcept {
4706
  // try to minimize the number of big integer and scalar multiplication.
4707
  // therefore, try to parse 8 digits at a time, and multiply by the largest
4708
  // scalar value (9 or 19 digits) for each step.
4709
0
  size_t counter = 0;
4710
0
  digits = 0;
4711
0
  limb value = 0;
4712
0
#ifdef FASTFLOAT_64BIT_LIMB
4713
0
  size_t step = 19;
4714
#else
4715
  size_t step = 9;
4716
#endif
4717
4718
  // process all integer digits.
4719
0
  UC const *p = num.integer.ptr;
4720
0
  UC const *pend = p + num.integer.len();
4721
0
  skip_zeros(p, pend);
4722
  // process all digits, in increments of step per loop
4723
0
  while (p != pend) {
4724
0
    while ((tinyobj_ff::distance(p, pend) >= 8) && (step - counter >= 8) &&
4725
0
           (max_digits - digits >= 8)) {
4726
0
      parse_eight_digits(p, value, counter, digits);
4727
0
    }
4728
0
    while (counter < step && p != pend && digits < max_digits) {
4729
0
      parse_one_digit(p, value, counter, digits);
4730
0
    }
4731
0
    if (digits == max_digits) {
4732
      // add the temporary value, then check if we've truncated any digits
4733
0
      add_native(result, limb(powers_of_ten_uint64[counter]), value);
4734
0
      bool truncated = is_truncated(p, pend);
4735
0
      if (num.fraction.ptr != nullptr) {
4736
0
        truncated |= is_truncated(num.fraction);
4737
0
      }
4738
0
      if (truncated) {
4739
0
        round_up_bigint(result, digits);
4740
0
      }
4741
0
      return;
4742
0
    } else {
4743
0
      add_native(result, limb(powers_of_ten_uint64[counter]), value);
4744
0
      counter = 0;
4745
0
      value = 0;
4746
0
    }
4747
0
  }
4748
4749
  // add our fraction digits, if they're available.
4750
0
  if (num.fraction.ptr != nullptr) {
4751
0
    p = num.fraction.ptr;
4752
0
    pend = p + num.fraction.len();
4753
0
    if (digits == 0) {
4754
0
      skip_zeros(p, pend);
4755
0
    }
4756
    // process all digits, in increments of step per loop
4757
0
    while (p != pend) {
4758
0
      while ((tinyobj_ff::distance(p, pend) >= 8) && (step - counter >= 8) &&
4759
0
             (max_digits - digits >= 8)) {
4760
0
        parse_eight_digits(p, value, counter, digits);
4761
0
      }
4762
0
      while (counter < step && p != pend && digits < max_digits) {
4763
0
        parse_one_digit(p, value, counter, digits);
4764
0
      }
4765
0
      if (digits == max_digits) {
4766
        // add the temporary value, then check if we've truncated any digits
4767
0
        add_native(result, limb(powers_of_ten_uint64[counter]), value);
4768
0
        bool truncated = is_truncated(p, pend);
4769
0
        if (truncated) {
4770
0
          round_up_bigint(result, digits);
4771
0
        }
4772
0
        return;
4773
0
      } else {
4774
0
        add_native(result, limb(powers_of_ten_uint64[counter]), value);
4775
0
        counter = 0;
4776
0
        value = 0;
4777
0
      }
4778
0
    }
4779
0
  }
4780
4781
0
  if (counter != 0) {
4782
0
    add_native(result, limb(powers_of_ten_uint64[counter]), value);
4783
0
  }
4784
0
}
4785
4786
template <typename T>
4787
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4788
0
positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept {
4789
0
  FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
4790
0
  adjusted_mantissa answer;
4791
0
  bool truncated;
4792
0
  answer.mantissa = bigmant.hi64(truncated);
4793
0
  int bias = binary_format<T>::mantissa_explicit_bits() -
4794
0
             binary_format<T>::minimum_exponent();
4795
0
  answer.power2 = bigmant.bit_length() - 64 + bias;
4796
4797
0
  round<T>(answer, [truncated](adjusted_mantissa &a, int32_t shift) {
4798
0
    round_nearest_tie_even(
4799
0
        a, shift,
4800
0
        [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
4801
0
          return is_above || (is_halfway && truncated) ||
4802
0
                 (is_odd && is_halfway);
4803
0
        });
4804
0
  });
4805
4806
0
  return answer;
4807
0
}
4808
4809
// the scaling here is quite simple: we have, for the real digits `m * 10^e`,
4810
// and for the theoretical digits `n * 2^f`. Since `e` is always negative,
4811
// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`.
4812
// we then need to scale by `2^(f- e)`, and then the two significant digits
4813
// are of the same magnitude.
4814
template <typename T>
4815
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
4816
0
    bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
4817
0
  bigint &real_digits = bigmant;
4818
0
  int32_t real_exp = exponent;
4819
4820
  // get the value of `b`, rounded down, and get a bigint representation of b+h
4821
0
  adjusted_mantissa am_b = am;
4822
  // gcc7 buf: use a lambda to remove the noexcept qualifier bug with
4823
  // -Wnoexcept-type.
4824
0
  round<T>(am_b,
4825
0
           [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); });
4826
0
  T b;
4827
0
  to_float(false, am_b, b);
4828
0
  adjusted_mantissa theor = to_extended_halfway(b);
4829
0
  bigint theor_digits(theor.mantissa);
4830
0
  int32_t theor_exp = theor.power2;
4831
4832
  // scale real digits and theor digits to be same power.
4833
0
  int32_t pow2_exp = theor_exp - real_exp;
4834
0
  uint32_t pow5_exp = uint32_t(-real_exp);
4835
0
  if (pow5_exp != 0) {
4836
0
    FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));
4837
0
  }
4838
0
  if (pow2_exp > 0) {
4839
0
    FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp)));
4840
0
  } else if (pow2_exp < 0) {
4841
0
    FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
4842
0
  }
4843
4844
  // compare digits, and use it to director rounding
4845
0
  int ord = real_digits.compare(theor_digits);
4846
0
  adjusted_mantissa answer = am;
4847
0
  round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
4848
0
    round_nearest_tie_even(
4849
0
        a, shift, [ord](bool is_odd, bool _, bool __) -> bool {
4850
0
          (void)_;  // not needed, since we've done our comparison
4851
0
          (void)__; // not needed, since we've done our comparison
4852
0
          if (ord > 0) {
4853
0
            return true;
4854
0
          } else if (ord < 0) {
4855
0
            return false;
4856
0
          } else {
4857
0
            return is_odd;
4858
0
          }
4859
0
        });
4860
0
  });
4861
4862
0
  return answer;
4863
0
}
4864
4865
// parse the significant digits as a big integer to unambiguously round the
4866
// the significant digits. here, we are trying to determine how to round
4867
// an extended float representation close to `b+h`, halfway between `b`
4868
// (the float rounded-down) and `b+u`, the next positive float. this
4869
// algorithm is always correct, and uses one of two approaches. when
4870
// the exponent is positive relative to the significant digits (such as
4871
// 1234), we create a big-integer representation, get the high 64-bits,
4872
// determine if any lower bits are truncated, and use that to direct
4873
// rounding. in case of a negative exponent relative to the significant
4874
// digits (such as 1.2345), we create a theoretical representation of
4875
// `b` as a big-integer type, scaled to the same binary exponent as
4876
// the actual digits. we then compare the big integer representations
4877
// of both, and use that to direct rounding.
4878
template <typename T, typename UC>
4879
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
4880
0
digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am) noexcept {
4881
  // remove the invalid exponent bias
4882
0
  am.power2 -= invalid_am_bias;
4883
4884
0
  int32_t sci_exp = scientific_exponent(num);
4885
0
  size_t max_digits = binary_format<T>::max_digits();
4886
0
  size_t digits = 0;
4887
0
  bigint bigmant;
4888
0
  parse_mantissa(bigmant, num, max_digits, digits);
4889
  // can't underflow, since digits is at most max_digits.
4890
0
  int32_t exponent = sci_exp + 1 - int32_t(digits);
4891
0
  if (exponent >= 0) {
4892
0
    return positive_digit_comp<T>(bigmant, exponent);
4893
0
  } else {
4894
0
    return negative_digit_comp<T>(bigmant, am, exponent);
4895
0
  }
4896
0
}
4897
4898
} // namespace fast_float
4899
4900
#endif
4901
4902
#ifndef FASTFLOAT_PARSE_NUMBER_H
4903
#define FASTFLOAT_PARSE_NUMBER_H
4904
4905
4906
#include <cmath>
4907
#include <cstring>
4908
#include <limits>
4909
4910
namespace fast_float {
4911
4912
namespace detail {
4913
/**
4914
 * Special case +inf, -inf, nan, infinity, -infinity.
4915
 * The case comparisons could be made much faster given that we know that the
4916
 * strings a null-free and fixed.
4917
 **/
4918
template <typename T, typename UC>
4919
from_chars_result_t<UC>
4920
    FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last,
4921
2.29k
                                       T &value, chars_format fmt) noexcept {
4922
2.29k
  from_chars_result_t<UC> answer{};
4923
2.29k
  answer.ptr = first;
4924
2.29k
  answer.ec = tinyobj_ff::ff_errc(); // be optimistic
4925
  // assume first < last, so dereference without checks;
4926
2.29k
  bool const minusSign = (*first == UC('-'));
4927
  // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
4928
2.29k
  if ((*first == UC('-')) ||
4929
1.86k
      (uint64_t(fmt & chars_format::allow_leading_plus) &&
4930
1.86k
       (*first == UC('+')))) {
4931
459
    ++first;
4932
459
  }
4933
2.29k
  if (last - first >= 3) {
4934
311
    if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
4935
0
      answer.ptr = (first += 3);
4936
0
      value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
4937
0
                        : std::numeric_limits<T>::quiet_NaN();
4938
      // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7,
4939
      // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
4940
0
      if (first != last && *first == UC('(')) {
4941
0
        for (UC const *ptr = first + 1; ptr != last; ++ptr) {
4942
0
          if (*ptr == UC(')')) {
4943
0
            answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
4944
0
            break;
4945
0
          } else if (!((UC('a') <= *ptr && *ptr <= UC('z')) ||
4946
0
                       (UC('A') <= *ptr && *ptr <= UC('Z')) ||
4947
0
                       (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
4948
0
            break; // forbidden char, not nan(n-char-seq-opt)
4949
0
        }
4950
0
      }
4951
0
      return answer;
4952
0
    }
4953
311
    if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
4954
0
      if ((last - first >= 8) &&
4955
0
          fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
4956
0
        answer.ptr = first + 8;
4957
0
      } else {
4958
0
        answer.ptr = first + 3;
4959
0
      }
4960
0
      value = minusSign ? -std::numeric_limits<T>::infinity()
4961
0
                        : std::numeric_limits<T>::infinity();
4962
0
      return answer;
4963
0
    }
4964
311
  }
4965
2.29k
  answer.ec = tinyobj_ff::ff_errc::invalid_argument;
4966
2.29k
  return answer;
4967
2.29k
}
4968
4969
/**
4970
 * Returns true if the floating-pointing rounding mode is to 'nearest'.
4971
 * It is the default on most system. This function is meant to be inexpensive.
4972
 * Credit : @mwalcott3
4973
 */
4974
2.79k
fastfloat_really_inline bool rounds_to_nearest() noexcept {
4975
  // https://lemire.me/blog/2020/06/26/gcc-not-nearest/
4976
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
4977
  return false;
4978
#endif
4979
  // See
4980
  // A fast function to check your floating-point rounding mode
4981
  // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/
4982
  //
4983
  // This function is meant to be equivalent to :
4984
  // prior: #include <cfenv>
4985
  //  return fegetround() == FE_TONEAREST;
4986
  // However, it is expected to be much faster than the fegetround()
4987
  // function call.
4988
  //
4989
  // The volatile keyword prevents the compiler from computing the function
4990
  // at compile-time.
4991
  // There might be other ways to prevent compile-time optimizations (e.g.,
4992
  // asm). The value does not need to be std::numeric_limits<float>::min(), any
4993
  // small value so that 1 + x should round to 1 would do (after accounting for
4994
  // excess precision, as in 387 instructions).
4995
2.79k
  static float volatile fmin = std::numeric_limits<float>::min();
4996
2.79k
  float fmini = fmin; // we copy it so that it gets loaded at most once.
4997
//
4998
// Explanation:
4999
// Only when fegetround() == FE_TONEAREST do we have that
5000
// fmin + 1.0f == 1.0f - fmin.
5001
//
5002
// FE_UPWARD:
5003
//  fmin + 1.0f > 1
5004
//  1.0f - fmin == 1
5005
//
5006
// FE_DOWNWARD or  FE_TOWARDZERO:
5007
//  fmin + 1.0f == 1
5008
//  1.0f - fmin < 1
5009
//
5010
// Note: This may fail to be accurate if fast-math has been
5011
// enabled, as rounding conventions may not apply.
5012
#ifdef FASTFLOAT_VISUAL_STUDIO
5013
#pragma warning(push)
5014
//  todo: is there a VS warning?
5015
//  see
5016
//  https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
5017
#elif defined(__clang__)
5018
#pragma clang diagnostic push
5019
2.79k
#pragma clang diagnostic ignored "-Wfloat-equal"
5020
#elif defined(__GNUC__)
5021
#pragma GCC diagnostic push
5022
#pragma GCC diagnostic ignored "-Wfloat-equal"
5023
#endif
5024
2.79k
  return (fmini + 1.0f == 1.0f - fmini);
5025
#ifdef FASTFLOAT_VISUAL_STUDIO
5026
#pragma warning(pop)
5027
#elif defined(__clang__)
5028
#pragma clang diagnostic pop
5029
#elif defined(__GNUC__)
5030
#pragma GCC diagnostic pop
5031
#endif
5032
2.79k
}
5033
5034
} // namespace detail
5035
5036
template <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
5.14k
       parse_options_t<UC> options) noexcept {
5041
5.14k
    return from_chars_advanced(first, last, value, options);
5042
5.14k
  }
5043
};
5044
5045
#ifdef __STDCPP_FLOAT32_T__
5046
template <> 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 {
5051
    // if std::float32_t is defined, and we are in C++23 mode; macro set for
5052
    // float32; set value to float due to equivalence between float and
5053
    // float32_t
5054
    float val;
5055
    auto ret = from_chars_advanced(first, last, val, options);
5056
    value = val;
5057
    return ret;
5058
  }
5059
};
5060
#endif
5061
5062
#ifdef __STDCPP_FLOAT64_T__
5063
template <> 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 {
5068
    // if std::float64_t is defined, and we are in C++23 mode; macro set for
5069
    // float64; set value as double due to equivalence between double and
5070
    // float64_t
5071
    double val;
5072
    auto ret = from_chars_advanced(first, last, val, options);
5073
    value = val;
5074
    return ret;
5075
  }
5076
};
5077
#endif
5078
5079
template <typename T, typename UC, typename>
5080
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5081
from_chars(UC const *first, UC const *last, T &value,
5082
5.14k
           chars_format fmt /*= chars_format::general*/) noexcept {
5083
5.14k
  return from_chars_caller<T>::call(first, last, value,
5084
5.14k
                                    parse_options_t<UC>(fmt));
5085
5.14k
}
5086
5087
/**
5088
 * This function overload takes parsed_number_string_t structure that is created
5089
 * and populated either by from_chars_advanced function taking chars range and
5090
 * parsing options or other parsing custom function implemented by user.
5091
 */
5092
template <typename T, typename UC>
5093
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5094
2.84k
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
5095
5096
2.84k
  static_assert(is_supported_float_type<T>::value,
5097
2.84k
                "only some floating-point types are supported");
5098
2.84k
  static_assert(is_supported_char_type<UC>::value,
5099
2.84k
                "only char, wchar_t, char16_t and char32_t are supported");
5100
5101
2.84k
  from_chars_result_t<UC> answer;
5102
5103
2.84k
  answer.ec = tinyobj_ff::ff_errc(); // be optimistic
5104
2.84k
  answer.ptr = pns.lastmatch;
5105
  // The implementation of the Clinger's fast path is convoluted because
5106
  // we want round-to-nearest in all cases, irrespective of the rounding mode
5107
  // selected on the thread.
5108
  // We proceed optimistically, assuming that detail::rounds_to_nearest()
5109
  // returns true.
5110
2.84k
  if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
5111
2.82k
      pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
5112
2.80k
      !pns.too_many_digits) {
5113
    // Unfortunately, the conventional Clinger's fast path is only possible
5114
    // when the system rounds to the nearest float.
5115
    //
5116
    // We expect the next branch to almost always be selected.
5117
    // We could check it first (before the previous branch), but
5118
    // there might be performance advantages at having the check
5119
    // be last.
5120
2.79k
    if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
5121
      // We have that fegetround() == FE_TONEAREST.
5122
      // Next is Clinger's fast path.
5123
2.79k
      if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
5124
2.79k
        value = T(pns.mantissa);
5125
2.79k
        if (pns.exponent < 0) {
5126
85
          value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
5127
2.71k
        } else {
5128
2.71k
          value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
5129
2.71k
        }
5130
2.79k
        if (pns.negative) {
5131
8
          value = -value;
5132
8
        }
5133
2.79k
        return answer;
5134
2.79k
      }
5135
2.79k
    } else {
5136
      // We do not have that fegetround() == FE_TONEAREST.
5137
      // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
5138
      // proposal
5139
0
      if (pns.exponent >= 0 &&
5140
0
          pns.mantissa <=
5141
0
              binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
5142
0
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
5143
        // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
5144
0
        if (pns.mantissa == 0) {
5145
0
          value = pns.negative ? T(-0.) : T(0.);
5146
0
          return answer;
5147
0
        }
5148
0
#endif
5149
0
        value = T(pns.mantissa) *
5150
0
                binary_format<T>::exact_power_of_ten(pns.exponent);
5151
0
        if (pns.negative) {
5152
0
          value = -value;
5153
0
        }
5154
0
        return answer;
5155
0
      }
5156
0
    }
5157
2.79k
  }
5158
50
  adjusted_mantissa am =
5159
50
      compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
5160
50
  if (pns.too_many_digits && am.power2 >= 0) {
5161
10
    if (am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
5162
0
      am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
5163
0
    }
5164
10
  }
5165
  // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa)
5166
  // and we have an invalid power (am.power2 < 0), then we need to go the long
5167
  // way around again. This is very uncommon.
5168
50
  if (am.power2 < 0) {
5169
0
    am = digit_comp<T>(pns, am);
5170
0
  }
5171
50
  to_float(pns.negative, am, value);
5172
  // Test for over/underflow.
5173
50
  if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) ||
5174
31
      am.power2 == binary_format<T>::infinite_power()) {
5175
30
    answer.ec = tinyobj_ff::ff_errc::result_out_of_range;
5176
30
  }
5177
50
  return answer;
5178
2.84k
}
5179
5180
template <typename T, typename UC>
5181
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5182
from_chars_float_advanced(UC const *first, UC const *last, T &value,
5183
5.14k
                          parse_options_t<UC> options) noexcept {
5184
5185
5.14k
  static_assert(is_supported_float_type<T>::value,
5186
5.14k
                "only some floating-point types are supported");
5187
5.14k
  static_assert(is_supported_char_type<UC>::value,
5188
5.14k
                "only char, wchar_t, char16_t and char32_t are supported");
5189
5190
5.14k
  chars_format const fmt = detail::adjust_for_feature_macros(options.format);
5191
5192
5.14k
  from_chars_result_t<UC> answer;
5193
5.14k
  if (uint64_t(fmt & chars_format::skip_white_space)) {
5194
0
    while ((first != last) && fast_float::is_space(*first)) {
5195
0
      first++;
5196
0
    }
5197
0
  }
5198
5.14k
  if (first == last) {
5199
0
    answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5200
0
    answer.ptr = first;
5201
0
    return answer;
5202
0
  }
5203
5.14k
  parsed_number_string_t<UC> pns =
5204
5.14k
      uint64_t(fmt & detail::basic_json_fmt)
5205
5.14k
          ? parse_number_string<true, UC>(first, last, options)
5206
5.14k
          : parse_number_string<false, UC>(first, last, options);
5207
5.14k
  if (!pns.valid) {
5208
2.29k
    if (uint64_t(fmt & chars_format::no_infnan)) {
5209
0
      answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5210
0
      answer.ptr = first;
5211
0
      return answer;
5212
2.29k
    } else {
5213
2.29k
      return detail::parse_infnan(first, last, value, fmt);
5214
2.29k
    }
5215
2.29k
  }
5216
5217
  // call overload that takes parsed_number_string_t directly.
5218
2.84k
  return from_chars_advanced(pns, value);
5219
5.14k
}
5220
5221
template <typename T, typename UC, typename>
5222
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5223
from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
5224
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");
5229
5230
  parse_options_t<UC> options;
5231
  options.base = base;
5232
  return from_chars_advanced(first, last, value, options);
5233
}
5234
5235
template <typename T, typename UC>
5236
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5237
from_chars_int_advanced(UC const *first, UC const *last, T &value,
5238
                        parse_options_t<UC> options) noexcept {
5239
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");
5244
5245
  chars_format const fmt = detail::adjust_for_feature_macros(options.format);
5246
  int const base = options.base;
5247
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)) {
5251
      first++;
5252
    }
5253
  }
5254
  if (first == last || base < 2 || base > 36) {
5255
    answer.ec = tinyobj_ff::ff_errc::invalid_argument;
5256
    answer.ptr = first;
5257
    return answer;
5258
  }
5259
5260
  return parse_int_string(first, last, value, options);
5261
}
5262
5263
template <size_t TypeIx> struct from_chars_advanced_caller {
5264
  static_assert(TypeIx > 0, "unsupported type");
5265
};
5266
5267
template <> 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
5.14k
       parse_options_t<UC> options) noexcept {
5272
5.14k
    return from_chars_float_advanced(first, last, value, options);
5273
5.14k
  }
5274
};
5275
5276
template <> 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);
5282
  }
5283
};
5284
5285
template <typename T, typename UC>
5286
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
5287
from_chars_advanced(UC const *first, UC const *last, T &value,
5288
5.14k
                    parse_options_t<UC> options) noexcept {
5289
5.14k
  return from_chars_advanced_caller<
5290
5.14k
      size_t(is_supported_float_type<T>::value) +
5291
5.14k
      2 * size_t(is_supported_integer_type<T>::value)>::call(first, last, value,
5292
5.14k
                                                             options);
5293
5.14k
}
5294
5295
} // namespace fast_float
5296
5297
#endif
5298
5299
5300
// --- End embedded fast_float ---
5301
5302
// Clean up fast_float macros to avoid polluting the user's namespace.
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
5335
#undef FASTFLOAT_TRY
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
5342
5343
#endif  // TINYOBJLOADER_DISABLE_FAST_FLOAT
5344
5345
namespace tinyobj {
5346
5347
8.54k
MaterialReader::~MaterialReader() {}
5348
5349
// Byte-stream reader for bounds-checked text parsing.
5350
// Replaces raw `const char*` token pointers with `(buf, len, idx)` triple.
5351
// Every byte access is guarded by an EOF check.
5352
class StreamReader {
5353
 public:
5354
// Maximum number of bytes StreamReader will buffer from std::istream.
5355
// Define this macro to a larger value if your application needs to parse
5356
// very large streamed OBJ/MTL content.
5357
#ifndef TINYOBJLOADER_STREAM_READER_MAX_BYTES
5358
10.1k
#define TINYOBJLOADER_STREAM_READER_MAX_BYTES (size_t(256) * size_t(1024) * size_t(1024))
5359
#endif
5360
5361
  StreamReader(const char *buf, size_t length)
5362
0
      : buf_(buf), length_(length), idx_(0), line_num_(1), col_num_(1) {}
5363
5364
  // Non-copyable, non-movable: buf_ may point into owned_buf_.
5365
  StreamReader(const StreamReader &) /* = delete */;
5366
  StreamReader &operator=(const StreamReader &) /* = delete */;
5367
5368
  // Build from std::istream by reading all content into an internal buffer.
5369
10.1k
  explicit StreamReader(std::istream &is) : buf_(NULL), length_(0), idx_(0), line_num_(1), col_num_(1) {
5370
10.1k
    const size_t max_stream_bytes = TINYOBJLOADER_STREAM_READER_MAX_BYTES;
5371
10.1k
    std::streampos start_pos = is.tellg();
5372
10.1k
    bool can_seek = (start_pos != std::streampos(-1));
5373
10.1k
    if (can_seek) {
5374
10.1k
      is.seekg(0, std::ios::end);
5375
10.1k
      std::streampos end_pos = is.tellg();
5376
10.1k
      if (end_pos >= start_pos) {
5377
10.1k
        std::streamoff remaining_off = static_cast<std::streamoff>(end_pos - start_pos);
5378
10.1k
        is.seekg(start_pos);
5379
10.1k
        unsigned long long remaining_ull = static_cast<unsigned long long>(remaining_off);
5380
10.1k
        if (remaining_ull > static_cast<unsigned long long>((std::numeric_limits<size_t>::max)())) {
5381
0
          std::stringstream ss;
5382
0
          ss << "input stream too large for this platform (" << remaining_ull
5383
0
             << " bytes exceeds size_t max " << (std::numeric_limits<size_t>::max)() << ")\n";
5384
0
          push_error(ss.str());
5385
0
          buf_ = "";
5386
0
          length_ = 0;
5387
0
          return;
5388
0
        }
5389
10.1k
        size_t remaining_size = static_cast<size_t>(remaining_ull);
5390
10.1k
        if (remaining_size > max_stream_bytes) {
5391
0
          std::stringstream ss;
5392
0
          ss << "input stream too large (" << remaining_size
5393
0
             << " bytes exceeds limit " << max_stream_bytes << " bytes)\n";
5394
0
          push_error(ss.str());
5395
0
          buf_ = "";
5396
0
          length_ = 0;
5397
0
          return;
5398
0
        }
5399
10.1k
        owned_buf_.resize(remaining_size);
5400
10.1k
        if (remaining_size > 0) {
5401
9.48k
          is.read(&owned_buf_[0], static_cast<std::streamsize>(remaining_size));
5402
9.48k
        }
5403
10.1k
        size_t actually_read = static_cast<size_t>(is.gcount());
5404
10.1k
        owned_buf_.resize(actually_read);
5405
10.1k
      }
5406
10.1k
    }
5407
10.1k
    if (!can_seek || owned_buf_.empty()) {
5408
      // Stream doesn't support seeking, or seek probing failed.
5409
24
      if (can_seek) is.seekg(start_pos);
5410
24
      is.clear();
5411
24
      std::vector<char> content;
5412
24
      char chunk[4096];
5413
24
      size_t total_read = 0;
5414
24
      while (is.good()) {
5415
24
        is.read(chunk, static_cast<std::streamsize>(sizeof(chunk)));
5416
24
        std::streamsize nread = is.gcount();
5417
24
        if (nread <= 0) break;
5418
0
        size_t n = static_cast<size_t>(nread);
5419
0
        if (n > (max_stream_bytes - total_read)) {
5420
0
          std::stringstream ss;
5421
0
          ss << "input stream too large (exceeds limit " << max_stream_bytes
5422
0
             << " bytes)\n";
5423
0
          push_error(ss.str());
5424
0
          owned_buf_.clear();
5425
0
          buf_ = "";
5426
0
          length_ = 0;
5427
0
          return;
5428
0
        }
5429
0
        content.insert(content.end(), chunk, chunk + n);
5430
0
        total_read += n;
5431
0
      }
5432
24
      owned_buf_.swap(content);
5433
24
    }
5434
10.1k
    buf_ = owned_buf_.empty() ? "" : &owned_buf_[0];
5435
10.1k
    length_ = owned_buf_.size();
5436
10.1k
  }
5437
5438
16.6M
  bool eof() const { return idx_ >= length_; }
5439
0
  size_t tell() const { return idx_; }
5440
0
  size_t size() const { return length_; }
5441
1.76M
  size_t line_num() const { return line_num_; }
5442
0
  size_t col_num() const { return col_num_; }
5443
5444
30.7M
  char peek() const {
5445
30.7M
    if (idx_ >= length_) return '\0';
5446
30.7M
    return buf_[idx_];
5447
30.7M
  }
5448
5449
0
  char get() {
5450
0
    if (idx_ >= length_) return '\0';
5451
0
    char c = buf_[idx_++];
5452
0
    if (c == '\n') { line_num_++; col_num_ = 1; } else { col_num_++; }
5453
0
    return c;
5454
0
  }
5455
5456
18.9M
  void advance(size_t n) {
5457
34.9M
    for (size_t i = 0; i < n && idx_ < length_; i++) {
5458
15.9M
      if (buf_[idx_] == '\n') { line_num_++; col_num_ = 1; } else { col_num_++; }
5459
15.9M
      idx_++;
5460
15.9M
    }
5461
18.9M
  }
5462
5463
10.5M
  void skip_space() {
5464
10.6M
    while (idx_ < length_ && (buf_[idx_] == ' ' || buf_[idx_] == '\t')) {
5465
20.4k
      col_num_++;
5466
20.4k
      idx_++;
5467
20.4k
    }
5468
10.5M
  }
5469
5470
721k
  void skip_space_and_cr() {
5471
1.43M
    while (idx_ < length_ && (buf_[idx_] == ' ' || buf_[idx_] == '\t' || buf_[idx_] == '\r')) {
5472
716k
      col_num_++;
5473
716k
      idx_++;
5474
716k
    }
5475
721k
  }
5476
5477
1.89M
  void skip_line() {
5478
9.67M
    while (idx_ < length_) {
5479
9.66M
      char c = buf_[idx_];
5480
9.66M
      if (c == '\n') {
5481
1.60M
        idx_++;
5482
1.60M
        line_num_++;
5483
1.60M
        col_num_ = 1;
5484
1.60M
        return;
5485
1.60M
      }
5486
8.06M
      if (c == '\r') {
5487
281k
        idx_++;
5488
281k
        if (idx_ < length_ && buf_[idx_] == '\n') {
5489
505
          idx_++;
5490
505
        }
5491
281k
        line_num_++;
5492
281k
        col_num_ = 1;
5493
281k
        return;
5494
281k
      }
5495
7.77M
      col_num_++;
5496
7.77M
      idx_++;
5497
7.77M
    }
5498
1.89M
  }
5499
5500
4.09M
  bool at_line_end() const {
5501
4.09M
    if (idx_ >= length_) return true;
5502
4.09M
    char c = buf_[idx_];
5503
4.09M
    return (c == '\n' || c == '\r' || c == '\0');
5504
4.09M
  }
5505
5506
141k
  std::string read_line() {
5507
141k
    std::string result;
5508
27.7M
    while (idx_ < length_) {
5509
27.7M
      char c = buf_[idx_];
5510
27.7M
      if (c == '\n' || c == '\r') break;
5511
27.6M
      result += c;
5512
27.6M
      col_num_++;
5513
27.6M
      idx_++;
5514
27.6M
    }
5515
141k
    return result;
5516
141k
  }
5517
5518
  // Reads a whitespace-delimited token. Used by tests and as a general utility.
5519
0
  std::string read_token() {
5520
0
    skip_space();
5521
0
    std::string result;
5522
0
    while (idx_ < length_) {
5523
0
      char c = buf_[idx_];
5524
0
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
5525
0
      result += c;
5526
0
      col_num_++;
5527
0
      idx_++;
5528
0
    }
5529
0
    return result;
5530
0
  }
5531
5532
4.13M
  bool match(const char *prefix, size_t len) const {
5533
4.13M
    if (idx_ >= length_ || len > length_ - idx_) return false;
5534
4.12M
    return (memcmp(buf_ + idx_, prefix, len) == 0);
5535
4.13M
  }
5536
5537
0
  bool char_at(size_t offset, char c) const {
5538
0
    if (idx_ >= length_ || offset >= length_ - idx_) return false;
5539
0
    return buf_[idx_ + offset] == c;
5540
0
  }
5541
5542
2.52M
  char peek_at(size_t offset) const {
5543
2.52M
    if (idx_ >= length_ || offset >= length_ - idx_) return '\0';
5544
2.52M
    return buf_[idx_ + offset];
5545
2.52M
  }
5546
5547
6.25M
  const char *current_ptr() const {
5548
6.25M
    if (idx_ >= length_) return "";
5549
5.44M
    return buf_ + idx_;
5550
6.25M
  }
5551
5552
7.16M
  size_t remaining() const {
5553
7.16M
    return (idx_ < length_) ? (length_ - idx_) : 0;
5554
7.16M
  }
5555
5556
  // Returns the full text of the current line (for diagnostic display).
5557
1.05k
  std::string current_line_text() const {
5558
    // Scan backward to find line start
5559
1.05k
    size_t line_start = idx_;
5560
31.3k
    while (line_start > 0 && buf_[line_start - 1] != '\n' && buf_[line_start - 1] != '\r') {
5561
30.2k
      line_start--;
5562
30.2k
    }
5563
    // Scan forward to find line end
5564
1.05k
    size_t line_end = idx_;
5565
3.68M
    while (line_end < length_ && buf_[line_end] != '\n' && buf_[line_end] != '\r') {
5566
3.68M
      line_end++;
5567
3.68M
    }
5568
1.05k
    return std::string(buf_ + line_start, line_end - line_start);
5569
1.05k
  }
5570
5571
  // Clang-style formatted error with file:line:col and caret.
5572
1.05k
  std::string format_error(const std::string &filename, const std::string &msg) const {
5573
1.05k
    std::stringstream line_ss, col_ss;
5574
1.05k
    line_ss << line_num_;
5575
1.05k
    col_ss << col_num_;
5576
1.05k
    std::string result;
5577
1.05k
    result += filename + ":" + line_ss.str() + ":" + col_ss.str() + ": error: " + msg + "\n";
5578
1.05k
    std::string line_text = current_line_text();
5579
1.05k
    result += line_text + "\n";
5580
    // Build caret line preserving tab alignment
5581
1.05k
    std::string caret;
5582
1.05k
    size_t caret_pos = (col_num_ > 0) ? (col_num_ - 1) : 0;
5583
31.5k
    for (size_t i = 0; i < caret_pos && i < line_text.size(); i++) {
5584
30.5k
      caret += (line_text[i] == '\t') ? '\t' : ' ';
5585
30.5k
    }
5586
1.05k
    caret += "^";
5587
1.05k
    result += caret + "\n";
5588
1.05k
    return result;
5589
1.05k
  }
5590
5591
0
  std::string format_error(const std::string &msg) const {
5592
0
    return format_error("<input>", msg);
5593
0
  }
5594
5595
  // Error stack
5596
0
  void push_error(const std::string &msg) {
5597
0
    errors_.push_back(msg);
5598
0
  }
5599
5600
0
  void push_formatted_error(const std::string &filename, const std::string &msg) {
5601
0
    errors_.push_back(format_error(filename, msg));
5602
0
  }
5603
5604
10.1k
  bool has_errors() const { return !errors_.empty(); }
5605
5606
0
  std::string get_errors() const {
5607
0
    std::string result;
5608
0
    for (size_t i = 0; i < errors_.size(); i++) {
5609
0
      result += errors_[i];
5610
0
    }
5611
0
    return result;
5612
0
  }
5613
5614
0
  const std::vector<std::string> &error_stack() const { return errors_; }
5615
5616
0
  void clear_errors() { errors_.clear(); }
5617
5618
 private:
5619
  const char *buf_;
5620
  size_t length_;
5621
  size_t idx_;
5622
  size_t line_num_;
5623
  size_t col_num_;
5624
  std::vector<char> owned_buf_;
5625
  std::vector<std::string> errors_;
5626
};
5627
5628
#ifdef TINYOBJLOADER_USE_MMAP
5629
// RAII wrapper for memory-mapped file I/O.
5630
// Opens a file and maps it into memory; the mapping is released on destruction.
5631
// For empty files, data is set to "" and is_mapped remains false so close()
5632
// will not attempt to unmap a string literal.
5633
struct MappedFile {
5634
  const char *data;
5635
  size_t size;
5636
  bool is_mapped;  // true when data points to an actual mapped region
5637
#if defined(_WIN32)
5638
  HANDLE hFile;
5639
  HANDLE hMapping;
5640
#else
5641
  void *mapped_ptr;
5642
#endif
5643
5644
  MappedFile() : data(NULL), size(0), is_mapped(false)
5645
#if defined(_WIN32)
5646
    , hFile(INVALID_HANDLE_VALUE), hMapping(NULL)
5647
#else
5648
    , mapped_ptr(NULL)
5649
#endif
5650
  {}
5651
5652
  // Opens and maps the file. Returns true on success.
5653
  bool open(const char *filepath) {
5654
#if defined(_WIN32)
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)())) {
5664
      close();
5665
      return false;
5666
    }
5667
    size = static_cast<size_t>(fsize);
5668
    if (size == 0) { data = ""; return true; }  // valid but empty; is_mapped stays false
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; }
5673
    is_mapped = true;
5674
    return true;
5675
#else
5676
    int fd = ::open(filepath, O_RDONLY);
5677
    if (fd == -1) return false;
5678
    struct stat sb;
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)())) {
5683
      ::close(fd);
5684
      return false;
5685
    }
5686
    size = static_cast<size_t>(sb.st_size);
5687
    if (size == 0) { ::close(fd); data = ""; return true; }  // valid but empty
5688
    mapped_ptr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
5689
    ::close(fd);
5690
    if (mapped_ptr == MAP_FAILED) { mapped_ptr = NULL; size = 0; return false; }
5691
    data = static_cast<const char *>(mapped_ptr);
5692
    is_mapped = true;
5693
    return true;
5694
#endif
5695
  }
5696
5697
  void close() {
5698
#if defined(_WIN32)
5699
    if (is_mapped && data) { UnmapViewOfFile(data); }
5700
    data = NULL;
5701
    is_mapped = false;
5702
    if (hMapping != NULL) { CloseHandle(hMapping); hMapping = NULL; }
5703
    if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; }
5704
#else
5705
    if (is_mapped && mapped_ptr && mapped_ptr != MAP_FAILED) { munmap(mapped_ptr, size); }
5706
    mapped_ptr = NULL;
5707
    data = NULL;
5708
    is_mapped = false;
5709
#endif
5710
    size = 0;
5711
  }
5712
5713
  ~MappedFile() { close(); }
5714
5715
 private:
5716
  MappedFile(const MappedFile &);             // non-copyable
5717
  MappedFile &operator=(const MappedFile &);  // non-copyable
5718
};
5719
#endif  // TINYOBJLOADER_USE_MMAP
5720
5721
5722
struct vertex_index_t {
5723
  int v_idx, vt_idx, vn_idx;
5724
190k
  vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
5725
188k
  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
0
      : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
5728
};
5729
5730
// Internal data structure for face representation
5731
// index + smoothing group.
5732
struct face_t {
5733
  unsigned int
5734
      smoothing_group_id;  // smoothing group id. 0 = smoothing groupd is off.
5735
  int pad_;
5736
  std::vector<vertex_index_t> vertex_indices;  // face vertex indices.
5737
5738
458k
  face_t() : smoothing_group_id(0), pad_(0) {}
5739
};
5740
5741
// Internal data structure for line representation
5742
struct __line_t {
5743
  // l v1/vt1 v2/vt2 ...
5744
  // In the specification, line primitrive does not have normal index, but
5745
  // TinyObjLoader allow it
5746
  std::vector<vertex_index_t> vertex_indices;
5747
};
5748
5749
// Internal data structure for points representation
5750
struct __points_t {
5751
  // p v1 v2 ...
5752
  // In the specification, point primitrive does not have normal index and
5753
  // texture coord index, but TinyObjLoader allow it.
5754
  std::vector<vertex_index_t> vertex_indices;
5755
};
5756
5757
struct tag_sizes {
5758
574k
  tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
5759
  int num_ints;
5760
  int num_reals;
5761
  int num_strings;
5762
};
5763
5764
struct obj_shape {
5765
  std::vector<real_t> v;
5766
  std::vector<real_t> vn;
5767
  std::vector<real_t> vt;
5768
};
5769
5770
//
5771
// Manages group of primitives(face, line, points, ...)
5772
struct PrimGroup {
5773
  std::vector<face_t> faceGroup;
5774
  std::vector<__line_t> lineGroup;
5775
  std::vector<__points_t> pointsGroup;
5776
5777
19.7k
  void clear() {
5778
19.7k
    faceGroup.clear();
5779
19.7k
    lineGroup.clear();
5780
19.7k
    pointsGroup.clear();
5781
19.7k
  }
5782
5783
19.7k
  bool IsEmpty() const {
5784
19.7k
    return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty();
5785
19.7k
  }
5786
5787
  // TODO(syoyo): bspline, surface, ...
5788
};
5789
5790
// See
5791
// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
5792
594k
#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
11.5k
#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
5796
5797
template <typename T>
5798
1.88k
static inline std::string toString(const T &t) {
5799
1.88k
  std::stringstream ss;
5800
1.88k
  ss << t;
5801
1.88k
  return ss.str();
5802
1.88k
}
5803
5804
0
static inline std::string removeUtf8Bom(const std::string& input) {
5805
0
    // UTF-8 BOM = 0xEF,0xBB,0xBF
5806
0
    if (input.size() >= 3 &&
5807
0
        static_cast<unsigned char>(input[0]) == 0xEF &&
5808
0
        static_cast<unsigned char>(input[1]) == 0xBB &&
5809
0
        static_cast<unsigned char>(input[2]) == 0xBF) {
5810
0
        return input.substr(3); // Skip BOM
5811
0
    }
5812
0
    return input;
5813
0
}
5814
5815
// Trim trailing spaces and tabs from a string.
5816
132k
static inline std::string trimTrailingWhitespace(const std::string &s) {
5817
132k
  size_t end = s.find_last_not_of(" \t");
5818
132k
  if (end == std::string::npos) return "";
5819
126k
  return s.substr(0, end + 1);
5820
132k
}
5821
5822
struct warning_context {
5823
  std::string *warn;
5824
  size_t line_number;
5825
  std::string filename;
5826
};
5827
5828
// Safely convert size_t to int, clamping at INT_MAX to prevent overflow.
5829
582k
static inline int size_to_int(size_t sz) {
5830
582k
  return sz > static_cast<size_t>(INT_MAX) ? INT_MAX : static_cast<int>(sz);
5831
582k
}
5832
5833
// Make index zero-base, and also support relative index.
5834
static inline bool fixIndex(int idx, int n, int *ret, bool allow_zero,
5835
188k
                            const warning_context &context) {
5836
188k
  if (!ret) {
5837
0
    return false;
5838
0
  }
5839
5840
188k
  if (idx > 0) {
5841
187k
    (*ret) = idx - 1;
5842
187k
    return true;
5843
187k
  }
5844
5845
1.93k
  if (idx == 0) {
5846
    // zero is not allowed according to the spec.
5847
1.88k
    if (context.warn) {
5848
1.88k
      (*context.warn) +=
5849
1.88k
          context.filename + ":" + toString(context.line_number) +
5850
1.88k
          ": warning: zero value index found (will have a value of -1 for "
5851
1.88k
          "normal and tex indices)\n";
5852
1.88k
    }
5853
5854
1.88k
    (*ret) = idx - 1;
5855
1.88k
    return allow_zero;
5856
1.88k
  }
5857
5858
47
  if (idx < 0) {
5859
47
    (*ret) = n + idx;  // negative value = relative
5860
47
    if ((*ret) < 0) {
5861
40
      return false;  // invalid relative index
5862
40
    }
5863
7
    return true;
5864
47
  }
5865
5866
0
  return false;  // never reach here.
5867
47
}
5868
5869
264
static inline std::string parseString(const char **token) {
5870
264
  std::string s;
5871
264
  (*token) += strspn((*token), " \t");
5872
264
  size_t e = strcspn((*token), " \t\r");
5873
264
  s = std::string((*token), &(*token)[e]);
5874
264
  (*token) += e;
5875
264
  return s;
5876
264
}
5877
5878
223
static inline int parseInt(const char **token) {
5879
223
  (*token) += strspn((*token), " \t");
5880
223
  int i = atoi((*token));
5881
223
  (*token) += strcspn((*token), " \t\r");
5882
223
  return i;
5883
223
}
5884
5885
#ifndef TINYOBJLOADER_DISABLE_FAST_FLOAT
5886
5887
// ---- fast_float-based float parser (bit-exact with strtod, ~3x faster) ----
5888
5889
namespace detail_fp {
5890
5891
// Case-insensitive prefix match. Returns pointer past matched prefix, or NULL.
5892
static inline const char *match_iprefix(const char *p, const char *end,
5893
129
                                        const char *prefix) {
5894
177
  while (*prefix) {
5895
177
    if (p == end) return NULL;
5896
160
    char c = *p;
5897
160
    char e = *prefix;
5898
160
    if (c >= 'A' && c <= 'Z') c += 32;
5899
160
    if (e >= 'A' && e <= 'Z') e += 32;
5900
160
    if (c != e) return NULL;
5901
48
    ++p;
5902
48
    ++prefix;
5903
48
  }
5904
0
  return p;
5905
129
}
5906
5907
// Try to parse nan/inf. Returns true if matched, sets *result and *end_ptr.
5908
static inline bool tryParseNanInf(const char *first, const char *last,
5909
43
                                  double *result, const char **end_ptr) {
5910
43
  if (first >= last) return false;
5911
5912
43
  const char *p = first;
5913
43
  bool negative = false;
5914
5915
43
  if (*p == '-') {
5916
1
    negative = true;
5917
1
    ++p;
5918
42
  } else if (*p == '+') {
5919
0
    ++p;
5920
0
  }
5921
5922
43
  if (p >= last) return false;
5923
5924
  // Try "nan"
5925
43
  const char *after = match_iprefix(p, last, "nan");
5926
43
  if (after) {
5927
0
    *result = 0.0;  // nan -> 0.0 for OBJ
5928
0
    *end_ptr = after;
5929
0
    return true;
5930
0
  }
5931
5932
  // Try "infinity" first (longer match), then "inf"
5933
43
  after = match_iprefix(p, last, "infinity");
5934
43
  if (after) {
5935
0
    *result = negative ? std::numeric_limits<double>::lowest()
5936
0
                       : (std::numeric_limits<double>::max)();
5937
0
    *end_ptr = after;
5938
0
    return true;
5939
0
  }
5940
5941
43
  after = match_iprefix(p, last, "inf");
5942
43
  if (after) {
5943
0
    *result = negative ? std::numeric_limits<double>::lowest()
5944
0
                       : (std::numeric_limits<double>::max)();
5945
0
    *end_ptr = after;
5946
0
    return true;
5947
0
  }
5948
5949
43
  return false;
5950
43
}
5951
5952
}  // namespace detail_fp
5953
5954
// Tries to parse a floating point number located at s.
5955
// Uses fast_float::from_chars for bit-exact, high-performance parsing.
5956
// Handles OBJ quirks: leading '+', nan/inf with replacement values.
5957
//
5958
// s_end should be a location in the string where reading should absolutely
5959
// stop. For example at the end of the string, to prevent buffer overflows.
5960
//
5961
// If the parsing is a success, result is set to the parsed value and true
5962
// is returned.
5963
//
5964
5.66k
static bool tryParseDouble(const char *s, const char *s_end, double *result) {
5965
5.66k
  if (!s || !s_end || !result || s >= s_end) {
5966
524
    return false;
5967
524
  }
5968
5969
  // Check for nan/inf (starts with [nNiI] or [+-] followed by [nNiI])
5970
5.14k
  const char *p = s;
5971
5.14k
  if (p < s_end && (*p == '+' || *p == '-')) ++p;
5972
5.14k
  if (p < s_end) {
5973
4.78k
    char fc = *p;
5974
4.78k
    if (fc >= 'A' && fc <= 'Z') fc += 32;
5975
4.78k
    if (fc == 'n' || fc == 'i') {
5976
43
      const char *end_ptr;
5977
43
      if (detail_fp::tryParseNanInf(s, s_end, result, &end_ptr)) {
5978
0
        return true;
5979
0
      }
5980
43
    }
5981
4.78k
  }
5982
5983
  // Use allow_leading_plus so fast_float handles '+' natively.
5984
5.14k
  double tmp;
5985
5.14k
  auto r = fast_float::from_chars(s, s_end, tmp,
5986
5.14k
      fast_float::chars_format::general |
5987
5.14k
      fast_float::chars_format::allow_leading_plus);
5988
5.14k
  if (r.ec == tinyobj_ff::ff_errc::ok) {
5989
2.81k
    *result = tmp;
5990
2.81k
    return true;
5991
2.81k
  }
5992
  // On error (invalid_argument, result_out_of_range), *result is unchanged.
5993
5994
2.32k
  return false;
5995
5.14k
}
5996
5997
1.95k
static inline real_t parseReal(const char **token, double default_value = 0.0) {
5998
1.95k
  (*token) += strspn((*token), " \t");
5999
1.95k
  const char *end = (*token) + strcspn((*token), " \t\r");
6000
1.95k
  double val = default_value;
6001
1.95k
  tryParseDouble((*token), end, &val);
6002
1.95k
  real_t f = static_cast<real_t>(val);
6003
1.95k
  (*token) = end;
6004
1.95k
  return f;
6005
1.95k
}
6006
6007
0
static inline bool parseReal(const char **token, real_t *out) {
6008
0
  (*token) += strspn((*token), " \t");
6009
0
  const char *end = (*token) + strcspn((*token), " \t\r");
6010
0
  double val;
6011
0
  bool ret = tryParseDouble((*token), end, &val);
6012
0
  if (ret) {
6013
0
    real_t f = static_cast<real_t>(val);
6014
0
    (*out) = f;
6015
0
  }
6016
0
  (*token) = end;
6017
0
  return ret;
6018
0
}
6019
6020
#else  // TINYOBJLOADER_DISABLE_FAST_FLOAT
6021
6022
// ---- Legacy hand-written float parser (fallback) ----
6023
6024
// Tries to parse a floating point number located at s.
6025
//
6026
// s_end should be a location in the string where reading should absolutely
6027
// stop. For example at the end of the string, to prevent buffer overflows.
6028
//
6029
// Parses the following EBNF grammar:
6030
//   sign    = "+" | "-" ;
6031
//   END     = ? anything not in digit ?
6032
//   digit   = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
6033
//   integer = [sign] , digit , {digit} ;
6034
//   decimal = integer , ["." , integer] ;
6035
//   float   = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
6036
//
6037
//  Valid strings are for example:
6038
//   -0  +3.1417e+2  -0.0E-3  1.0324  -1.41   11e2
6039
//
6040
// If the parsing is a success, result is set to the parsed value and true
6041
// is returned.
6042
//
6043
// The function is greedy and will parse until any of the following happens:
6044
//  - a non-conforming character is encountered.
6045
//  - s_end is reached.
6046
//
6047
// The following situations triggers a failure:
6048
//  - s >= s_end.
6049
//  - parse failure.
6050
//
6051
static bool tryParseDouble(const char *s, const char *s_end, double *result) {
6052
  if (s >= s_end) {
6053
    return false;
6054
  }
6055
6056
  double mantissa = 0.0;
6057
  // This exponent is base 2 rather than 10.
6058
  // However the exponent we parse is supposed to be one of ten,
6059
  // thus we must take care to convert the exponent/and or the
6060
  // mantissa to a * 2^E, where a is the mantissa and E is the
6061
  // exponent.
6062
  // To get the final double we will use ldexp, it requires the
6063
  // exponent to be in base 2.
6064
  int exponent = 0;
6065
6066
  // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED
6067
  // TO JUMP OVER DEFINITIONS.
6068
  char sign = '+';
6069
  char exp_sign = '+';
6070
  char const *curr = s;
6071
6072
  // How many characters were read in a loop.
6073
  int read = 0;
6074
  // Tells whether a loop terminated due to reaching s_end.
6075
  bool end_not_reached = false;
6076
  bool leading_decimal_dots = false;
6077
6078
  /*
6079
          BEGIN PARSING.
6080
  */
6081
6082
  // Find out what sign we've got.
6083
  if (*curr == '+' || *curr == '-') {
6084
    sign = *curr;
6085
    curr++;
6086
    if ((curr != s_end) && (*curr == '.')) {
6087
      // accept. Somethig like `.7e+2`, `-.5234`
6088
      leading_decimal_dots = true;
6089
    }
6090
  } else if (IS_DIGIT(*curr)) { /* Pass through. */
6091
  } else if (*curr == '.') {
6092
    // accept. Somethig like `.7e+2`, `-.5234`
6093
    leading_decimal_dots = true;
6094
  } else {
6095
    goto fail;
6096
  }
6097
6098
  // Read the integer part.
6099
  end_not_reached = (curr != s_end);
6100
  if (!leading_decimal_dots) {
6101
    while (end_not_reached && IS_DIGIT(*curr)) {
6102
      mantissa *= 10;
6103
      mantissa += static_cast<int>(*curr - 0x30);
6104
      curr++;
6105
      read++;
6106
      end_not_reached = (curr != s_end);
6107
    }
6108
6109
    // We must make sure we actually got something.
6110
    if (read == 0) goto fail;
6111
  }
6112
6113
  // We allow numbers of form "#", "###" etc.
6114
  if (!end_not_reached) goto assemble;
6115
6116
  // Read the decimal part.
6117
  if (*curr == '.') {
6118
    curr++;
6119
    read = 1;
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,
6124
      };
6125
      const int lut_entries = sizeof pow_lut / sizeof pow_lut[0];
6126
6127
      // NOTE: Don't use powf here, it will absolutely murder precision.
6128
      mantissa += static_cast<int>(*curr - 0x30) *
6129
                  (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read));
6130
      read++;
6131
      curr++;
6132
      end_not_reached = (curr != s_end);
6133
    }
6134
  } else if (*curr == 'e' || *curr == 'E') {
6135
  } else {
6136
    goto assemble;
6137
  }
6138
6139
  if (!end_not_reached) goto assemble;
6140
6141
  // Read the exponent part.
6142
  if (*curr == 'e' || *curr == 'E') {
6143
    curr++;
6144
    // Figure out if a sign is present and if it is.
6145
    end_not_reached = (curr != s_end);
6146
    if (end_not_reached && (*curr == '+' || *curr == '-')) {
6147
      exp_sign = *curr;
6148
      curr++;
6149
    } else if (IS_DIGIT(*curr)) { /* Pass through. */
6150
    } else {
6151
      // Empty E is not allowed.
6152
      goto fail;
6153
    }
6154
6155
    read = 0;
6156
    end_not_reached = (curr != s_end);
6157
    while (end_not_reached && IS_DIGIT(*curr)) {
6158
      // To avoid annoying MSVC's min/max macro definiton,
6159
      // Use hardcoded int max value
6160
      if (exponent >
6161
          ((2147483647 - 9) / 10)) {  // (INT_MAX - 9) / 10, guards both multiply and add
6162
        // Integer overflow
6163
        goto fail;
6164
      }
6165
      exponent *= 10;
6166
      exponent += static_cast<int>(*curr - 0x30);
6167
      curr++;
6168
      read++;
6169
      end_not_reached = (curr != s_end);
6170
    }
6171
    exponent *= (exp_sign == '+' ? 1 : -1);
6172
    if (read == 0) goto fail;
6173
  }
6174
6175
assemble:
6176
  *result = (sign == '+' ? 1 : -1) *
6177
            (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
6178
                      : mantissa);
6179
  return true;
6180
fail:
6181
  return false;
6182
}
6183
6184
static 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);
6190
  (*token) = end;
6191
  return f;
6192
}
6193
6194
static inline bool parseReal(const char **token, real_t *out) {
6195
  (*token) += strspn((*token), " \t");
6196
  const char *end = (*token) + strcspn((*token), " \t\r");
6197
  double val;
6198
  bool ret = tryParseDouble((*token), end, &val);
6199
  if (ret) {
6200
    real_t f = static_cast<real_t>(val);
6201
    (*out) = f;
6202
  }
6203
  (*token) = end;
6204
  return ret;
6205
}
6206
6207
#endif  // TINYOBJLOADER_DISABLE_FAST_FLOAT
6208
6209
static inline void parseReal2(real_t *x, real_t *y, const char **token,
6210
                              const double default_x = 0.0,
6211
268
                              const double default_y = 0.0) {
6212
268
  (*x) = parseReal(token, default_x);
6213
268
  (*y) = parseReal(token, default_y);
6214
268
}
6215
6216
static 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
419
                              const double default_z = 0.0) {
6220
419
  (*x) = parseReal(token, default_x);
6221
419
  (*y) = parseReal(token, default_y);
6222
419
  (*z) = parseReal(token, default_z);
6223
419
}
6224
6225
#if 0  // not used
6226
static 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);
6235
}
6236
#endif
6237
6238
// Extension: parse vertex with colors(6 items)
6239
// Return 3: xyz, 4: xyzw, 6: xyzrgb
6240
// `r`: red(case 6) or [w](case 4)
6241
static inline int parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6242
                                       real_t *r, real_t *g, real_t *b,
6243
                                       const char **token,
6244
                                       const double default_x = 0.0,
6245
                                       const double default_y = 0.0,
6246
0
                                       const double default_z = 0.0) {
6247
0
  // TODO: Check error
6248
0
  (*x) = parseReal(token, default_x);
6249
0
  (*y) = parseReal(token, default_y);
6250
0
  (*z) = parseReal(token, default_z);
6251
0
6252
0
  // - 4 components(x, y, z, w) ot 6 components
6253
0
  bool has_r = parseReal(token, r);
6254
0
6255
0
  if (!has_r) {
6256
0
    (*r) = (*g) = (*b) = 1.0;
6257
0
    return 3;
6258
0
  }
6259
0
6260
0
  bool has_g = parseReal(token, g);
6261
0
6262
0
  if (!has_g) {
6263
0
    (*g) = (*b) = 1.0;
6264
0
    return 4;
6265
0
  }
6266
0
6267
0
  bool has_b = parseReal(token, b);
6268
0
6269
0
  if (!has_b) {
6270
0
    (*r) = (*g) = (*b) = 1.0;
6271
0
    return 3;  // treated as xyz
6272
0
  }
6273
0
6274
0
  return 6;
6275
0
}
6276
6277
854
static inline bool parseOnOff(const char **token, bool default_value = true) {
6278
854
  (*token) += strspn((*token), " \t");
6279
854
  const char *end = (*token) + strcspn((*token), " \t\r");
6280
6281
854
  bool ret = default_value;
6282
854
  if ((0 == strncmp((*token), "on", 2))) {
6283
138
    ret = true;
6284
716
  } else if ((0 == strncmp((*token), "off", 3))) {
6285
185
    ret = false;
6286
185
  }
6287
6288
854
  (*token) = end;
6289
854
  return ret;
6290
854
}
6291
6292
static inline texture_type_t parseTextureType(
6293
46
    const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) {
6294
46
  (*token) += strspn((*token), " \t");
6295
46
  const char *end = (*token) + strcspn((*token), " \t\r");
6296
46
  texture_type_t ty = default_value;
6297
6298
46
  if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) {
6299
0
    ty = TEXTURE_TYPE_CUBE_TOP;
6300
46
  } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) {
6301
0
    ty = TEXTURE_TYPE_CUBE_BOTTOM;
6302
46
  } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) {
6303
4
    ty = TEXTURE_TYPE_CUBE_LEFT;
6304
42
  } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) {
6305
5
    ty = TEXTURE_TYPE_CUBE_RIGHT;
6306
37
  } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) {
6307
0
    ty = TEXTURE_TYPE_CUBE_FRONT;
6308
37
  } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) {
6309
0
    ty = TEXTURE_TYPE_CUBE_BACK;
6310
37
  } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) {
6311
7
    ty = TEXTURE_TYPE_SPHERE;
6312
7
  }
6313
6314
46
  (*token) = end;
6315
46
  return ty;
6316
46
}
6317
6318
0
static tag_sizes parseTagTriple(const char **token) {
6319
0
  tag_sizes ts;
6320
0
6321
0
  (*token) += strspn((*token), " \t");
6322
0
  ts.num_ints = atoi((*token));
6323
0
  (*token) += strcspn((*token), "/ \t\r");
6324
0
  if ((*token)[0] != '/') {
6325
0
    return ts;
6326
0
  }
6327
0
6328
0
  (*token)++;  // Skip '/'
6329
0
6330
0
  (*token) += strspn((*token), " \t");
6331
0
  ts.num_reals = atoi((*token));
6332
0
  (*token) += strcspn((*token), "/ \t\r");
6333
0
  if ((*token)[0] != '/') {
6334
0
    return ts;
6335
0
  }
6336
0
  (*token)++;  // Skip '/'
6337
0
6338
0
  ts.num_strings = parseInt(token);
6339
0
6340
0
  return ts;
6341
0
}
6342
6343
// Parse triples with index offsets: i, i/j/k, i//k, i/j
6344
static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
6345
0
                        vertex_index_t *ret, const warning_context &context) {
6346
0
  if (!ret) {
6347
0
    return false;
6348
0
  }
6349
0
6350
0
  vertex_index_t vi(-1);
6351
0
6352
0
  if (!fixIndex(atoi((*token)), vsize, &vi.v_idx, false, context)) {
6353
0
    return false;
6354
0
  }
6355
0
6356
0
  (*token) += strcspn((*token), "/ \t\r");
6357
0
  if ((*token)[0] != '/') {
6358
0
    (*ret) = vi;
6359
0
    return true;
6360
0
  }
6361
0
  (*token)++;
6362
0
6363
0
  // i//k
6364
0
  if ((*token)[0] == '/') {
6365
0
    (*token)++;
6366
0
    if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx, true, context)) {
6367
0
      return false;
6368
0
    }
6369
0
    (*token) += strcspn((*token), "/ \t\r");
6370
0
    (*ret) = vi;
6371
0
    return true;
6372
0
  }
6373
0
6374
0
  // i/j/k or i/j
6375
0
  if (!fixIndex(atoi((*token)), vtsize, &vi.vt_idx, true, context)) {
6376
0
    return false;
6377
0
  }
6378
0
6379
0
  (*token) += strcspn((*token), "/ \t\r");
6380
0
  if ((*token)[0] != '/') {
6381
0
    (*ret) = vi;
6382
0
    return true;
6383
0
  }
6384
0
6385
0
  // i/j/k
6386
0
  (*token)++;  // skip '/'
6387
0
  if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx, true, context)) {
6388
0
    return false;
6389
0
  }
6390
0
  (*token) += strcspn((*token), "/ \t\r");
6391
0
6392
0
  (*ret) = vi;
6393
0
6394
0
  return true;
6395
0
}
6396
6397
// Parse raw triples: i, i/j/k, i//k, i/j
6398
0
static vertex_index_t parseRawTriple(const char **token) {
6399
0
  vertex_index_t vi(static_cast<int>(0));  // 0 is an invalid index in OBJ
6400
0
6401
0
  vi.v_idx = atoi((*token));
6402
0
  (*token) += strcspn((*token), "/ \t\r");
6403
0
  if ((*token)[0] != '/') {
6404
0
    return vi;
6405
0
  }
6406
0
  (*token)++;
6407
0
6408
0
  // i//k
6409
0
  if ((*token)[0] == '/') {
6410
0
    (*token)++;
6411
0
    vi.vn_idx = atoi((*token));
6412
0
    (*token) += strcspn((*token), "/ \t\r");
6413
0
    return vi;
6414
0
  }
6415
0
6416
0
  // i/j/k or i/j
6417
0
  vi.vt_idx = atoi((*token));
6418
0
  (*token) += strcspn((*token), "/ \t\r");
6419
0
  if ((*token)[0] != '/') {
6420
0
    return vi;
6421
0
  }
6422
0
6423
0
  // i/j/k
6424
0
  (*token)++;  // skip '/'
6425
0
  vi.vn_idx = atoi((*token));
6426
0
  (*token) += strcspn((*token), "/ \t\r");
6427
0
  return vi;
6428
0
}
6429
6430
// --- Stream-based parse functions ---
6431
6432
1.98M
static inline std::string sr_parseString(StreamReader &sr) {
6433
1.98M
  sr.skip_space();
6434
1.98M
  std::string s;
6435
13.0M
  while (!sr.eof()) {
6436
12.7M
    char c = sr.peek();
6437
12.7M
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6438
11.0M
    s += c;
6439
11.0M
    sr.advance(1);
6440
11.0M
  }
6441
1.98M
  return s;
6442
1.98M
}
6443
6444
3.22M
static inline int sr_parseInt(StreamReader &sr) {
6445
3.22M
  sr.skip_space();
6446
3.22M
  const char *start = sr.current_ptr();
6447
3.22M
  size_t rem = sr.remaining();
6448
3.22M
  size_t len = 0;
6449
4.41M
  while (len < rem) {
6450
4.04M
    char c = start[len];
6451
4.04M
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6452
1.19M
    len++;
6453
1.19M
  }
6454
3.22M
  int i = 0;
6455
3.22M
  if (len > 0) {
6456
2.78k
    char tmp[64];
6457
2.78k
    size_t copy_len = len < 63 ? len : 63;
6458
2.78k
    if (copy_len != len) {
6459
11
      sr.advance(len);
6460
11
      return 0;
6461
11
    }
6462
2.77k
    memcpy(tmp, start, copy_len);
6463
2.77k
    tmp[copy_len] = '\0';
6464
2.77k
    errno = 0;
6465
2.77k
    char *endptr = NULL;
6466
2.77k
    long val = strtol(tmp, &endptr, 10);
6467
2.77k
    const bool has_error =
6468
2.77k
        (errno == ERANGE || endptr == tmp ||
6469
1.84k
         val > (std::numeric_limits<int>::max)() ||
6470
1.83k
         val < (std::numeric_limits<int>::min)());
6471
2.77k
    if (!has_error) {
6472
1.83k
      i = static_cast<int>(val);
6473
1.83k
    }
6474
2.77k
  }
6475
3.22M
  sr.advance(len);
6476
3.22M
  return i;
6477
3.22M
}
6478
6479
2.24M
static inline real_t sr_parseReal(StreamReader &sr, double default_value = 0.0) {
6480
2.24M
  sr.skip_space();
6481
2.24M
  const char *start = sr.current_ptr();
6482
2.24M
  size_t rem = sr.remaining();
6483
2.24M
  size_t len = 0;
6484
2.25M
  while (len < rem) {
6485
1.81M
    char c = start[len];
6486
1.81M
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6487
9.48k
    len++;
6488
9.48k
  }
6489
2.24M
  double val = default_value;
6490
2.24M
  if (len > 0) {
6491
641
    tryParseDouble(start, start + len, &val);
6492
641
  }
6493
2.24M
  sr.advance(len);
6494
2.24M
  return static_cast<real_t>(val);
6495
2.24M
}
6496
6497
4.33k
static inline bool sr_parseReal(StreamReader &sr, real_t *out) {
6498
4.33k
  sr.skip_space();
6499
4.33k
  const char *start = sr.current_ptr();
6500
4.33k
  size_t rem = sr.remaining();
6501
4.33k
  size_t len = 0;
6502
5.08k
  while (len < rem) {
6503
4.74k
    char c = start[len];
6504
4.74k
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6505
750
    len++;
6506
750
  }
6507
4.33k
  if (len == 0) return false;
6508
538
  double val;
6509
538
  bool ret = tryParseDouble(start, start + len, &val);
6510
538
  if (ret) {
6511
299
    (*out) = static_cast<real_t>(val);
6512
299
  }
6513
538
  sr.advance(len);
6514
538
  return ret;
6515
4.33k
}
6516
6517
static inline void sr_parseReal2(real_t *x, real_t *y, StreamReader &sr,
6518
                                 const double default_x = 0.0,
6519
136
                                 const double default_y = 0.0) {
6520
136
  (*x) = sr_parseReal(sr, default_x);
6521
136
  (*y) = sr_parseReal(sr, default_y);
6522
136
}
6523
6524
static inline void sr_parseReal3(real_t *x, real_t *y, real_t *z,
6525
                                 StreamReader &sr,
6526
                                 const double default_x = 0.0,
6527
                                 const double default_y = 0.0,
6528
0
                                 const double default_z = 0.0) {
6529
0
  (*x) = sr_parseReal(sr, default_x);
6530
0
  (*y) = sr_parseReal(sr, default_y);
6531
0
  (*z) = sr_parseReal(sr, default_z);
6532
0
}
6533
6534
static inline int sr_parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6535
                                          real_t *r, real_t *g, real_t *b,
6536
                                          StreamReader &sr,
6537
                                          const double default_x = 0.0,
6538
                                          const double default_y = 0.0,
6539
0
                                          const double default_z = 0.0) {
6540
0
  (*x) = sr_parseReal(sr, default_x);
6541
0
  (*y) = sr_parseReal(sr, default_y);
6542
0
  (*z) = sr_parseReal(sr, default_z);
6543
0
6544
0
  bool has_r = sr_parseReal(sr, r);
6545
0
  if (!has_r) {
6546
0
    (*r) = (*g) = (*b) = 1.0;
6547
0
    return 3;
6548
0
  }
6549
0
6550
0
  bool has_g = sr_parseReal(sr, g);
6551
0
  if (!has_g) {
6552
0
    (*g) = (*b) = 1.0;
6553
0
    return 4;
6554
0
  }
6555
0
6556
0
  bool has_b = sr_parseReal(sr, b);
6557
0
  if (!has_b) {
6558
0
    (*r) = (*g) = (*b) = 1.0;
6559
0
    return 3;
6560
0
  }
6561
0
6562
0
  return 6;
6563
0
}
6564
6565
// --- Error-reporting overloads ---
6566
// These overloads push clang-style diagnostics into `err` when parsing fails
6567
// and return false so callers can early-return on unrecoverable parse errors.
6568
// The original signatures are preserved above for backward compatibility.
6569
6570
static inline bool sr_parseInt(StreamReader &sr, int *out, std::string *err,
6571
170
                               const std::string &filename) {
6572
170
  sr.skip_space();
6573
170
  const char *start = sr.current_ptr();
6574
170
  size_t rem = sr.remaining();
6575
170
  size_t len = 0;
6576
314
  while (len < rem) {
6577
312
    char c = start[len];
6578
312
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6579
144
    len++;
6580
144
  }
6581
170
  if (len == 0) {
6582
43
    if (err) {
6583
43
      (*err) += sr.format_error(filename, "expected integer value");
6584
43
    }
6585
43
    *out = 0;
6586
43
    return false;
6587
43
  }
6588
127
  char tmp[64];
6589
127
  size_t copy_len = len < 63 ? len : 63;
6590
127
  memcpy(tmp, start, copy_len);
6591
127
  tmp[copy_len] = '\0';
6592
127
  if (copy_len != len) {
6593
0
    if (err) {
6594
0
      (*err) += sr.format_error(filename, "integer value too long");
6595
0
    }
6596
0
    *out = 0;
6597
0
    sr.advance(len);
6598
0
    return false;
6599
0
  }
6600
127
  errno = 0;
6601
127
  char *endptr = NULL;
6602
127
  long val = strtol(tmp, &endptr, 10);
6603
127
  if (errno == ERANGE || val > (std::numeric_limits<int>::max)() ||
6604
127
      val < (std::numeric_limits<int>::min)()) {
6605
0
    if (err) {
6606
0
      (*err) += sr.format_error(filename,
6607
0
          "integer value out of range, got '" + std::string(tmp) + "'");
6608
0
    }
6609
0
    *out = 0;
6610
0
    sr.advance(len);
6611
0
    return false;
6612
0
  }
6613
127
  if (endptr == tmp || (*endptr != '\0' && *endptr != ' ' && *endptr != '\t')) {
6614
115
    if (err) {
6615
115
      (*err) += sr.format_error(filename,
6616
115
          "expected integer, got '" + std::string(tmp) + "'");
6617
115
    }
6618
115
    *out = 0;
6619
115
    sr.advance(len);
6620
115
    return false;
6621
115
  }
6622
12
  *out = static_cast<int>(val);
6623
12
  sr.advance(len);
6624
12
  return true;
6625
127
}
6626
6627
static inline bool sr_parseReal(StreamReader &sr, real_t *out,
6628
                                 double default_value,
6629
                                 std::string *err,
6630
14.4k
                                 const std::string &filename) {
6631
14.4k
  sr.skip_space();
6632
14.4k
  const char *start = sr.current_ptr();
6633
14.4k
  size_t rem = sr.remaining();
6634
14.4k
  size_t len = 0;
6635
45.1k
  while (len < rem) {
6636
44.1k
    char c = start[len];
6637
44.1k
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0') break;
6638
30.7k
    len++;
6639
30.7k
  }
6640
14.4k
  if (len == 0) {
6641
    // No token to parse — not necessarily an error (e.g. optional component).
6642
11.9k
    *out = static_cast<real_t>(default_value);
6643
11.9k
    return true;
6644
11.9k
  }
6645
2.52k
  double val;
6646
2.52k
  if (!tryParseDouble(start, start + len, &val)) {
6647
485
    if (err) {
6648
485
      char tmp[64];
6649
485
      size_t copy_len = len < 63 ? len : 63;
6650
485
      memcpy(tmp, start, copy_len);
6651
485
      tmp[copy_len] = '\0';
6652
485
      (*err) += sr.format_error(filename,
6653
485
          "expected number, got '" + std::string(tmp) + "'");
6654
485
    }
6655
485
    *out = static_cast<real_t>(default_value);
6656
485
    sr.advance(len);
6657
485
    return false;
6658
485
  }
6659
2.04k
  *out = static_cast<real_t>(val);
6660
2.04k
  sr.advance(len);
6661
2.04k
  return true;
6662
2.52k
}
6663
6664
static inline bool sr_parseReal2(real_t *x, real_t *y, StreamReader &sr,
6665
                                  std::string *err,
6666
                                  const std::string &filename,
6667
                                  const double default_x = 0.0,
6668
1.05k
                                  const double default_y = 0.0) {
6669
1.05k
  if (!sr_parseReal(sr, x, default_x, err, filename)) return false;
6670
1.05k
  if (!sr_parseReal(sr, y, default_y, err, filename)) return false;
6671
1.05k
  return true;
6672
1.05k
}
6673
6674
static inline bool sr_parseReal3(real_t *x, real_t *y, real_t *z,
6675
                                  StreamReader &sr,
6676
                                  std::string *err,
6677
                                  const std::string &filename,
6678
                                  const double default_x = 0.0,
6679
                                  const double default_y = 0.0,
6680
961
                                  const double default_z = 0.0) {
6681
961
  if (!sr_parseReal(sr, x, default_x, err, filename)) return false;
6682
926
  if (!sr_parseReal(sr, y, default_y, err, filename)) return false;
6683
926
  if (!sr_parseReal(sr, z, default_z, err, filename)) return false;
6684
926
  return true;
6685
926
}
6686
6687
// Returns number of components parsed (3, 4, or 6) on success, -1 on error.
6688
static inline int sr_parseVertexWithColor(real_t *x, real_t *y, real_t *z,
6689
                                          real_t *r, real_t *g, real_t *b,
6690
                                          StreamReader &sr,
6691
                                          std::string *err,
6692
                                          const std::string &filename,
6693
                                          const double default_x = 0.0,
6694
                                          const double default_y = 0.0,
6695
3.39k
                                          const double default_z = 0.0) {
6696
3.39k
  if (!sr_parseReal(sr, x, default_x, err, filename)) return -1;
6697
3.03k
  if (!sr_parseReal(sr, y, default_y, err, filename)) return -1;
6698
3.01k
  if (!sr_parseReal(sr, z, default_z, err, filename)) return -1;
6699
6700
3.00k
  bool has_r = sr_parseReal(sr, r);
6701
3.00k
  if (!has_r) {
6702
2.75k
    (*r) = (*g) = (*b) = 1.0;
6703
2.75k
    return 3;
6704
2.75k
  }
6705
6706
249
  bool has_g = sr_parseReal(sr, g);
6707
249
  if (!has_g) {
6708
219
    (*g) = (*b) = 1.0;
6709
219
    return 4;
6710
219
  }
6711
6712
30
  bool has_b = sr_parseReal(sr, b);
6713
30
  if (!has_b) {
6714
11
    (*r) = (*g) = (*b) = 1.0;
6715
11
    return 3;
6716
11
  }
6717
6718
19
  return 6;
6719
30
}
6720
6721
static inline int sr_parseIntNoSkip(StreamReader &sr);
6722
6723
// Advance past remaining characters in a tag triple field (stops at '/', whitespace, or line end).
6724
576k
static inline void sr_skipTagField(StreamReader &sr) {
6725
582k
  while (!sr.eof() && !sr.at_line_end() && !IS_SPACE(sr.peek()) &&
6726
8.17k
         sr.peek() != '/') {
6727
5.69k
    sr.advance(1);
6728
5.69k
  }
6729
576k
}
6730
6731
574k
static tag_sizes sr_parseTagTriple(StreamReader &sr) {
6732
574k
  tag_sizes ts;
6733
6734
574k
  sr.skip_space();
6735
574k
  ts.num_ints = sr_parseIntNoSkip(sr);
6736
574k
  sr_skipTagField(sr);
6737
574k
  if (!sr.eof() && sr.peek() == '/') {
6738
1.71k
    sr.advance(1);
6739
1.71k
    sr.skip_space();
6740
1.71k
    ts.num_reals = sr_parseIntNoSkip(sr);
6741
1.71k
    sr_skipTagField(sr);
6742
1.71k
    if (!sr.eof() && sr.peek() == '/') {
6743
767
      sr.advance(1);
6744
767
      ts.num_strings = sr_parseInt(sr);
6745
767
    }
6746
1.71k
  }
6747
574k
  return ts;
6748
574k
}
6749
6750
765k
static inline int sr_parseIntNoSkip(StreamReader &sr) {
6751
765k
  const char *start = sr.current_ptr();
6752
765k
  size_t rem = sr.remaining();
6753
765k
  size_t len = 0;
6754
765k
  if (len < rem && (start[len] == '+' || start[len] == '-')) len++;
6755
974k
  while (len < rem && start[len] >= '0' && start[len] <= '9') len++;
6756
765k
  int i = 0;
6757
765k
  if (len > 0) {
6758
191k
    char tmp[64];
6759
191k
    size_t copy_len = len < 63 ? len : 63;
6760
191k
    if (copy_len != len) {
6761
0
      sr.advance(len);
6762
0
      return 0;
6763
0
    }
6764
191k
    memcpy(tmp, start, copy_len);
6765
191k
    tmp[copy_len] = '\0';
6766
191k
    errno = 0;
6767
191k
    char *endptr = NULL;
6768
191k
    long val = strtol(tmp, &endptr, 10);
6769
191k
    if (errno == 0 && endptr != tmp && *endptr == '\0' &&
6770
191k
        val <= (std::numeric_limits<int>::max)() &&
6771
191k
        val >= (std::numeric_limits<int>::min)()) {
6772
191k
      i = static_cast<int>(val);
6773
191k
    }
6774
191k
  }
6775
765k
  sr.advance(len);
6776
765k
  return i;
6777
765k
}
6778
6779
188k
static inline void sr_skipUntil(StreamReader &sr, const char *delims) {
6780
284k
  while (!sr.eof()) {
6781
284k
    char c = sr.peek();
6782
1.14M
    for (const char *d = delims; *d; d++) {
6783
1.05M
      if (c == *d) return;
6784
1.05M
    }
6785
96.0k
    sr.advance(1);
6786
96.0k
  }
6787
188k
}
6788
6789
static bool sr_parseTriple(StreamReader &sr, int vsize, int vnsize, int vtsize,
6790
186k
                           vertex_index_t *ret, const warning_context &context) {
6791
186k
  if (!ret) return false;
6792
6793
186k
  vertex_index_t vi(-1);
6794
6795
186k
  sr.skip_space();
6796
186k
  if (!fixIndex(sr_parseIntNoSkip(sr), vsize, &vi.v_idx, false, context)) {
6797
399
    return false;
6798
399
  }
6799
6800
186k
  sr_skipUntil(sr, "/ \t\r\n");
6801
186k
  if (sr.eof() || sr.peek() != '/') {
6802
184k
    (*ret) = vi;
6803
184k
    return true;
6804
184k
  }
6805
1.89k
  sr.advance(1);
6806
6807
  // i//k
6808
1.89k
  if (!sr.eof() && sr.peek() == '/') {
6809
318
    sr.advance(1);
6810
318
    if (!fixIndex(sr_parseIntNoSkip(sr), vnsize, &vi.vn_idx, true, context)) {
6811
1
      return false;
6812
1
    }
6813
317
    sr_skipUntil(sr, "/ \t\r\n");
6814
317
    (*ret) = vi;
6815
317
    return true;
6816
318
  }
6817
6818
  // i/j/k or i/j
6819
1.58k
  if (!fixIndex(sr_parseIntNoSkip(sr), vtsize, &vi.vt_idx, true, context)) {
6820
3
    return false;
6821
3
  }
6822
6823
1.57k
  sr_skipUntil(sr, "/ \t\r\n");
6824
1.57k
  if (sr.eof() || sr.peek() != '/') {
6825
1.15k
    (*ret) = vi;
6826
1.15k
    return true;
6827
1.15k
  }
6828
6829
  // i/j/k
6830
426
  sr.advance(1);
6831
426
  if (!fixIndex(sr_parseIntNoSkip(sr), vnsize, &vi.vn_idx, true, context)) {
6832
1
    return false;
6833
1
  }
6834
425
  sr_skipUntil(sr, "/ \t\r\n");
6835
6836
425
  (*ret) = vi;
6837
425
  return true;
6838
426
}
6839
6840
0
static vertex_index_t sr_parseRawTriple(StreamReader &sr) {
6841
0
  vertex_index_t vi(static_cast<int>(0));
6842
6843
0
  sr.skip_space();
6844
0
  vi.v_idx = sr_parseIntNoSkip(sr);
6845
0
  sr_skipUntil(sr, "/ \t\r\n");
6846
0
  if (sr.eof() || sr.peek() != '/') return vi;
6847
0
  sr.advance(1);
6848
6849
  // i//k
6850
0
  if (!sr.eof() && sr.peek() == '/') {
6851
0
    sr.advance(1);
6852
0
    vi.vn_idx = sr_parseIntNoSkip(sr);
6853
0
    sr_skipUntil(sr, "/ \t\r\n");
6854
0
    return vi;
6855
0
  }
6856
6857
  // i/j/k or i/j
6858
0
  vi.vt_idx = sr_parseIntNoSkip(sr);
6859
0
  sr_skipUntil(sr, "/ \t\r\n");
6860
0
  if (sr.eof() || sr.peek() != '/') return vi;
6861
6862
0
  sr.advance(1);
6863
0
  vi.vn_idx = sr_parseIntNoSkip(sr);
6864
0
  sr_skipUntil(sr, "/ \t\r\n");
6865
0
  return vi;
6866
0
}
6867
6868
bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt,
6869
4.90k
                               const char *linebuf) {
6870
  // @todo { write more robust lexer and parser. }
6871
4.90k
  bool found_texname = false;
6872
4.90k
  std::string texture_name;
6873
6874
4.90k
  const char *token = linebuf;  // Assume line ends with NULL
6875
6876
11.5k
  while (!IS_NEW_LINE((*token))) {
6877
6.64k
    token += strspn(token, " \t");  // skip space
6878
6.64k
    if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) {
6879
407
      token += 8;
6880
407
      texopt->blendu = parseOnOff(&token, /* default */ true);
6881
6.24k
    } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) {
6882
209
      token += 8;
6883
209
      texopt->blendv = parseOnOff(&token, /* default */ true);
6884
6.03k
    } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) {
6885
238
      token += 7;
6886
238
      texopt->clamp = parseOnOff(&token, /* default */ true);
6887
5.79k
    } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) {
6888
145
      token += 7;
6889
145
      texopt->sharpness = parseReal(&token, 1.0);
6890
5.64k
    } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) {
6891
20
      token += 4;
6892
20
      texopt->bump_multiplier = parseReal(&token, 1.0);
6893
5.62k
    } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) {
6894
5
      token += 3;
6895
5
      parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]),
6896
5
                 &(texopt->origin_offset[2]), &token);
6897
5.62k
    } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) {
6898
373
      token += 3;
6899
373
      parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]),
6900
373
                 &token, 1.0, 1.0, 1.0);
6901
5.25k
    } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) {
6902
41
      token += 3;
6903
41
      parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]),
6904
41
                 &(texopt->turbulence[2]), &token);
6905
5.21k
    } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) {
6906
46
      token += 5;
6907
46
      texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE);
6908
5.16k
    } else if ((0 == strncmp(token, "-texres", 7)) && IS_SPACE((token[7]))) {
6909
223
      token += 7;
6910
      // TODO(syoyo): Check if arg is int type.
6911
223
      texopt->texture_resolution = parseInt(&token);
6912
4.94k
    } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) {
6913
94
      token += 9;
6914
94
      token += strspn(token, " \t");
6915
94
      const char *end = token + strcspn(token, " \t\r");
6916
94
      if ((end - token) == 1) {  // Assume one char for -imfchan
6917
77
        texopt->imfchan = (*token);
6918
77
      }
6919
94
      token = end;
6920
4.84k
    } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) {
6921
268
      token += 4;
6922
268
      parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
6923
4.57k
    } else if ((0 == strncmp(token, "-colorspace", 11)) &&
6924
425
               IS_SPACE((token[11]))) {
6925
264
      token += 12;
6926
264
      texopt->colorspace = parseString(&token);
6927
4.31k
    } else {
6928
// Assume texture filename
6929
#if 0
6930
      size_t len = strcspn(token, " \t\r");  // untile next space
6931
      texture_name = std::string(token, token + len);
6932
      token += len;
6933
6934
      token += strspn(token, " \t");  // skip space
6935
#else
6936
      // Read filename until line end to parse filename containing whitespace
6937
      // TODO(syoyo): Support parsing texture option flag after the filename.
6938
4.31k
      texture_name = std::string(token);
6939
4.31k
      token += texture_name.length();
6940
4.31k
#endif
6941
6942
4.31k
      found_texname = true;
6943
4.31k
    }
6944
6.64k
  }
6945
6946
4.90k
  if (found_texname) {
6947
4.31k
    (*texname) = texture_name;
6948
4.31k
    return true;
6949
4.31k
  } else {
6950
588
    return false;
6951
588
  }
6952
4.90k
}
6953
6954
557k
static void InitTexOpt(texture_option_t *texopt, const bool is_bump) {
6955
557k
  if (is_bump) {
6956
42.8k
    texopt->imfchan = 'l';
6957
514k
  } else {
6958
514k
    texopt->imfchan = 'm';
6959
514k
  }
6960
557k
  texopt->bump_multiplier = static_cast<real_t>(1.0);
6961
557k
  texopt->clamp = false;
6962
557k
  texopt->blendu = true;
6963
557k
  texopt->blendv = true;
6964
557k
  texopt->sharpness = static_cast<real_t>(1.0);
6965
557k
  texopt->brightness = static_cast<real_t>(0.0);
6966
557k
  texopt->contrast = static_cast<real_t>(1.0);
6967
557k
  texopt->origin_offset[0] = static_cast<real_t>(0.0);
6968
557k
  texopt->origin_offset[1] = static_cast<real_t>(0.0);
6969
557k
  texopt->origin_offset[2] = static_cast<real_t>(0.0);
6970
557k
  texopt->scale[0] = static_cast<real_t>(1.0);
6971
557k
  texopt->scale[1] = static_cast<real_t>(1.0);
6972
557k
  texopt->scale[2] = static_cast<real_t>(1.0);
6973
557k
  texopt->turbulence[0] = static_cast<real_t>(0.0);
6974
557k
  texopt->turbulence[1] = static_cast<real_t>(0.0);
6975
557k
  texopt->turbulence[2] = static_cast<real_t>(0.0);
6976
557k
  texopt->texture_resolution = -1;
6977
557k
  texopt->type = TEXTURE_TYPE_NONE;
6978
557k
}
6979
6980
42.8k
static void InitMaterial(material_t *material) {
6981
42.8k
  InitTexOpt(&material->ambient_texopt, /* is_bump */ false);
6982
42.8k
  InitTexOpt(&material->diffuse_texopt, /* is_bump */ false);
6983
42.8k
  InitTexOpt(&material->specular_texopt, /* is_bump */ false);
6984
42.8k
  InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false);
6985
42.8k
  InitTexOpt(&material->bump_texopt, /* is_bump */ true);
6986
42.8k
  InitTexOpt(&material->displacement_texopt, /* is_bump */ false);
6987
42.8k
  InitTexOpt(&material->alpha_texopt, /* is_bump */ false);
6988
42.8k
  InitTexOpt(&material->reflection_texopt, /* is_bump */ false);
6989
42.8k
  InitTexOpt(&material->roughness_texopt, /* is_bump */ false);
6990
42.8k
  InitTexOpt(&material->metallic_texopt, /* is_bump */ false);
6991
42.8k
  InitTexOpt(&material->sheen_texopt, /* is_bump */ false);
6992
42.8k
  InitTexOpt(&material->emissive_texopt, /* is_bump */ false);
6993
42.8k
  InitTexOpt(&material->normal_texopt,
6994
42.8k
             /* is_bump */ false);  // @fixme { is_bump will be true? }
6995
42.8k
  material->name = "";
6996
42.8k
  material->ambient_texname = "";
6997
42.8k
  material->diffuse_texname = "";
6998
42.8k
  material->specular_texname = "";
6999
42.8k
  material->specular_highlight_texname = "";
7000
42.8k
  material->bump_texname = "";
7001
42.8k
  material->displacement_texname = "";
7002
42.8k
  material->reflection_texname = "";
7003
42.8k
  material->alpha_texname = "";
7004
171k
  for (int i = 0; i < 3; i++) {
7005
128k
    material->ambient[i] = static_cast<real_t>(0.0);
7006
128k
    material->diffuse[i] = static_cast<real_t>(0.0);
7007
128k
    material->specular[i] = static_cast<real_t>(0.0);
7008
128k
    material->transmittance[i] = static_cast<real_t>(0.0);
7009
128k
    material->emission[i] = static_cast<real_t>(0.0);
7010
128k
  }
7011
42.8k
  material->illum = 0;
7012
42.8k
  material->dissolve = static_cast<real_t>(1.0);
7013
42.8k
  material->shininess = static_cast<real_t>(1.0);
7014
42.8k
  material->ior = static_cast<real_t>(1.0);
7015
7016
42.8k
  material->roughness = static_cast<real_t>(0.0);
7017
42.8k
  material->metallic = static_cast<real_t>(0.0);
7018
42.8k
  material->sheen = static_cast<real_t>(0.0);
7019
42.8k
  material->clearcoat_thickness = static_cast<real_t>(0.0);
7020
42.8k
  material->clearcoat_roughness = static_cast<real_t>(0.0);
7021
42.8k
  material->anisotropy_rotation = static_cast<real_t>(0.0);
7022
42.8k
  material->anisotropy = static_cast<real_t>(0.0);
7023
42.8k
  material->roughness_texname = "";
7024
42.8k
  material->metallic_texname = "";
7025
42.8k
  material->sheen_texname = "";
7026
42.8k
  material->emissive_texname = "";
7027
42.8k
  material->normal_texname = "";
7028
7029
42.8k
  material->unknown_parameter.clear();
7030
42.8k
}
7031
7032
// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
7033
template <typename T>
7034
25.5M
static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) {
7035
25.5M
  int i, j, c = 0;
7036
102M
  for (i = 0, j = nvert - 1; i < nvert; j = i++) {
7037
76.6M
    if (((verty[i] > testy) != (verty[j] > testy)) &&
7038
5.01k
        (testx <
7039
5.01k
         (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) +
7040
5.01k
             vertx[i]))
7041
1.31k
      c = !c;
7042
76.6M
  }
7043
25.5M
  return c;
7044
25.5M
}
7045
7046
struct TinyObjPoint {
7047
  real_t x, y, z;
7048
0
  TinyObjPoint() : x(0), y(0), z(0) {}
7049
0
  TinyObjPoint(real_t x_, real_t y_, real_t z_) : x(x_), y(y_), z(z_) {}
7050
};
7051
7052
0
inline TinyObjPoint cross(const TinyObjPoint &v1, const TinyObjPoint &v2) {
7053
0
  return TinyObjPoint(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z,
7054
0
                      v1.x * v2.y - v1.y * v2.x);
7055
0
}
7056
7057
0
inline real_t dot(const TinyObjPoint &v1, const TinyObjPoint &v2) {
7058
0
  return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
7059
0
}
7060
7061
0
inline real_t GetLength(TinyObjPoint &e) {
7062
0
  return std::sqrt(e.x * e.x + e.y * e.y + e.z * e.z);
7063
0
}
7064
7065
0
inline TinyObjPoint Normalize(TinyObjPoint e) {
7066
0
  real_t len = GetLength(e);
7067
0
  if (len <= real_t(0)) return TinyObjPoint(real_t(0), real_t(0), real_t(0));
7068
0
  real_t inv_length = real_t(1) / len;
7069
0
  return TinyObjPoint(e.x * inv_length, e.y * inv_length, e.z * inv_length);
7070
0
}
7071
7072
inline TinyObjPoint WorldToLocal(const TinyObjPoint &a, const TinyObjPoint &u,
7073
0
                                 const TinyObjPoint &v, const TinyObjPoint &w) {
7074
0
  return TinyObjPoint(dot(a, u), dot(a, v), dot(a, w));
7075
0
}
7076
7077
// TODO(syoyo): refactor function.
7078
static 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
19.7k
                                std::string *warn) {
7083
19.7k
  if (prim_group.IsEmpty()) {
7084
10.1k
    return false;
7085
10.1k
  }
7086
7087
9.52k
  shape->name = name;
7088
7089
  // polygon
7090
9.52k
  if (!prim_group.faceGroup.empty()) {
7091
    // Flatten vertices and indices
7092
460k
    for (size_t i = 0; i < prim_group.faceGroup.size(); i++) {
7093
457k
      const face_t &face = prim_group.faceGroup[i];
7094
7095
457k
      size_t npolys = face.vertex_indices.size();
7096
7097
457k
      if (npolys < 3) {
7098
        // Face must have 3+ vertices.
7099
452k
        if (warn) {
7100
452k
          (*warn) += "Degenerated face found\n.";
7101
452k
        }
7102
452k
        continue;
7103
452k
      }
7104
7105
4.71k
      if (triangulate && npolys != 3) {
7106
3.43k
        if (npolys == 4) {
7107
1.97k
          vertex_index_t i0 = face.vertex_indices[0];
7108
1.97k
          vertex_index_t i1 = face.vertex_indices[1];
7109
1.97k
          vertex_index_t i2 = face.vertex_indices[2];
7110
1.97k
          vertex_index_t i3 = face.vertex_indices[3];
7111
7112
1.97k
          if (i0.v_idx < 0 || i1.v_idx < 0 || i2.v_idx < 0 || i3.v_idx < 0) {
7113
0
            if (warn) {
7114
0
              (*warn) += "Face with invalid vertex index found.\n";
7115
0
            }
7116
0
            continue;
7117
0
          }
7118
7119
1.97k
          size_t vi0 = size_t(i0.v_idx);
7120
1.97k
          size_t vi1 = size_t(i1.v_idx);
7121
1.97k
          size_t vi2 = size_t(i2.v_idx);
7122
1.97k
          size_t vi3 = size_t(i3.v_idx);
7123
7124
1.97k
          if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
7125
1.31k
              ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) {
7126
            // Invalid triangle.
7127
            // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
7128
1.25k
            if (warn) {
7129
1.25k
              (*warn) += "Face with invalid vertex index found.\n";
7130
1.25k
            }
7131
1.25k
            continue;
7132
1.25k
          }
7133
7134
726
          real_t v0x = v[vi0 * 3 + 0];
7135
726
          real_t v0y = v[vi0 * 3 + 1];
7136
726
          real_t v0z = v[vi0 * 3 + 2];
7137
726
          real_t v1x = v[vi1 * 3 + 0];
7138
726
          real_t v1y = v[vi1 * 3 + 1];
7139
726
          real_t v1z = v[vi1 * 3 + 2];
7140
726
          real_t v2x = v[vi2 * 3 + 0];
7141
726
          real_t v2y = v[vi2 * 3 + 1];
7142
726
          real_t v2z = v[vi2 * 3 + 2];
7143
726
          real_t v3x = v[vi3 * 3 + 0];
7144
726
          real_t v3y = v[vi3 * 3 + 1];
7145
726
          real_t v3z = v[vi3 * 3 + 2];
7146
7147
          // There are two candidates to split the quad into two triangles.
7148
          //
7149
          // Choose the shortest edge.
7150
          // TODO: Is it better to determine the edge to split by calculating
7151
          // the area of each triangle?
7152
          //
7153
          // +---+
7154
          // |\  |
7155
          // | \ |
7156
          // |  \|
7157
          // +---+
7158
          //
7159
          // +---+
7160
          // |  /|
7161
          // | / |
7162
          // |/  |
7163
          // +---+
7164
7165
726
          real_t e02x = v2x - v0x;
7166
726
          real_t e02y = v2y - v0y;
7167
726
          real_t e02z = v2z - v0z;
7168
726
          real_t e13x = v3x - v1x;
7169
726
          real_t e13y = v3y - v1y;
7170
726
          real_t e13z = v3z - v1z;
7171
7172
726
          real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z;
7173
726
          real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z;
7174
7175
726
          index_t idx0, idx1, idx2, idx3;
7176
7177
726
          idx0.vertex_index = i0.v_idx;
7178
726
          idx0.normal_index = i0.vn_idx;
7179
726
          idx0.texcoord_index = i0.vt_idx;
7180
726
          idx1.vertex_index = i1.v_idx;
7181
726
          idx1.normal_index = i1.vn_idx;
7182
726
          idx1.texcoord_index = i1.vt_idx;
7183
726
          idx2.vertex_index = i2.v_idx;
7184
726
          idx2.normal_index = i2.vn_idx;
7185
726
          idx2.texcoord_index = i2.vt_idx;
7186
726
          idx3.vertex_index = i3.v_idx;
7187
726
          idx3.normal_index = i3.vn_idx;
7188
726
          idx3.texcoord_index = i3.vt_idx;
7189
7190
726
          if (sqr02 < sqr13) {
7191
            // [0, 1, 2], [0, 2, 3]
7192
158
            shape->mesh.indices.push_back(idx0);
7193
158
            shape->mesh.indices.push_back(idx1);
7194
158
            shape->mesh.indices.push_back(idx2);
7195
7196
158
            shape->mesh.indices.push_back(idx0);
7197
158
            shape->mesh.indices.push_back(idx2);
7198
158
            shape->mesh.indices.push_back(idx3);
7199
568
          } else {
7200
            // [0, 1, 3], [1, 2, 3]
7201
568
            shape->mesh.indices.push_back(idx0);
7202
568
            shape->mesh.indices.push_back(idx1);
7203
568
            shape->mesh.indices.push_back(idx3);
7204
7205
568
            shape->mesh.indices.push_back(idx1);
7206
568
            shape->mesh.indices.push_back(idx2);
7207
568
            shape->mesh.indices.push_back(idx3);
7208
568
          }
7209
7210
          // Two triangle faces
7211
726
          shape->mesh.num_face_vertices.push_back(3);
7212
726
          shape->mesh.num_face_vertices.push_back(3);
7213
7214
726
          shape->mesh.material_ids.push_back(material_id);
7215
726
          shape->mesh.material_ids.push_back(material_id);
7216
7217
726
          shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
7218
726
          shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
7219
7220
1.45k
        } else {
7221
#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
7222
          // Validate all vertex indices before accessing the vertex array.
7223
          {
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()) {
7228
                valid_poly = false;
7229
                break;
7230
              }
7231
            }
7232
            if (!valid_poly) {
7233
              if (warn) {
7234
                (*warn) += "Face with invalid vertex index found.\n";
7235
              }
7236
              continue;
7237
            }
7238
          }
7239
7240
          vertex_index_t i0 = face.vertex_indices[0];
7241
          vertex_index_t i0_2 = i0;
7242
7243
          // TMW change: Find the normal axis of the polygon using Newell's
7244
          // method
7245
          TinyObjPoint n;
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);
7249
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);
7253
7254
            real_t v0x = v[vi0 * 3 + 0];
7255
            real_t v0y = v[vi0 * 3 + 1];
7256
            real_t v0z = v[vi0 * 3 + 2];
7257
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];
7261
7262
            const TinyObjPoint point1(v0x, v0y, v0z);
7263
            const TinyObjPoint point2(v0x_2, v0y_2, v0z_2);
7264
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);
7269
7270
            n.x += (a.y * b.z);
7271
            n.y += (a.z * b.x);
7272
            n.z += (a.x * b.y);
7273
          }
7274
          real_t length_n = GetLength(n);
7275
          // Check if zero length normal
7276
          if (length_n <= 0) {
7277
            continue;
7278
          }
7279
          // Negative is to flip the normal to the correct direction
7280
          real_t inv_length = -real_t(1.0) / length_n;
7281
          n.x *= inv_length;
7282
          n.y *= inv_length;
7283
          n.z *= inv_length;
7284
7285
          TinyObjPoint axis_w, axis_v, axis_u;
7286
          axis_w = n;
7287
          TinyObjPoint a;
7288
          if (std::fabs(axis_w.x) > real_t(0.9999999)) {
7289
            a = TinyObjPoint(0, 1, 0);
7290
          } else {
7291
            a = TinyObjPoint(1, 0, 0);
7292
          }
7293
          axis_v = Normalize(cross(axis_w, a));
7294
          axis_u = cross(axis_w, axis_v);
7295
          using Point = std::array<real_t, 2>;
7296
7297
          // first polyline define the main polygon.
7298
          // following polylines define holes(not used in tinyobj).
7299
          std::vector<std::vector<Point> > polygon;
7300
7301
          std::vector<Point> polyline;
7302
7303
          // TMW change: Find best normal and project v0x and v0y to those
7304
          // coordinates, instead of picking a plane aligned with an axis (which
7305
          // can flip polygons).
7306
7307
          // Fill polygon data(facevarying vertices).
7308
          for (size_t k = 0; k < npolys; k++) {
7309
            i0 = face.vertex_indices[k];
7310
            size_t vi0 = size_t(i0.v_idx);
7311
7312
            assert(((3 * vi0 + 2) < v.size()));
7313
7314
            real_t v0x = v[vi0 * 3 + 0];
7315
            real_t v0y = v[vi0 * 3 + 1];
7316
            real_t v0z = v[vi0 * 3 + 2];
7317
7318
            TinyObjPoint polypoint(v0x, v0y, v0z);
7319
            TinyObjPoint loc = WorldToLocal(polypoint, axis_u, axis_v, axis_w);
7320
7321
            polyline.push_back({loc.x, loc.y});
7322
          }
7323
7324
          polygon.push_back(polyline);
7325
          std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
7326
          // => result = 3 * faces, clockwise
7327
7328
          assert(indices.size() % 3 == 0);
7329
7330
          // Reconstruct vertex_index_t
7331
          for (size_t k = 0; k < indices.size() / 3; k++) {
7332
            {
7333
              index_t idx0, idx1, idx2;
7334
              idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx;
7335
              idx0.normal_index =
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;
7340
              idx1.normal_index =
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;
7345
              idx2.normal_index =
7346
                  face.vertex_indices[indices[3 * k + 2]].vn_idx;
7347
              idx2.texcoord_index =
7348
                  face.vertex_indices[indices[3 * k + 2]].vt_idx;
7349
7350
              shape->mesh.indices.push_back(idx0);
7351
              shape->mesh.indices.push_back(idx1);
7352
              shape->mesh.indices.push_back(idx2);
7353
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);
7358
            }
7359
          }
7360
7361
#else  // Built-in ear clipping triangulation
7362
1.45k
          vertex_index_t i0 = face.vertex_indices[0];
7363
1.45k
          vertex_index_t i1(-1);
7364
1.45k
          vertex_index_t i2 = face.vertex_indices[1];
7365
7366
          // find the two axes to work in
7367
1.45k
          size_t axes[2] = {1, 2};
7368
121k
          for (size_t k = 0; k < npolys; ++k) {
7369
120k
            i0 = face.vertex_indices[(k + 0) % npolys];
7370
120k
            i1 = face.vertex_indices[(k + 1) % npolys];
7371
120k
            i2 = face.vertex_indices[(k + 2) % npolys];
7372
120k
            size_t vi0 = size_t(i0.v_idx);
7373
120k
            size_t vi1 = size_t(i1.v_idx);
7374
120k
            size_t vi2 = size_t(i2.v_idx);
7375
7376
120k
            if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
7377
119k
                ((3 * vi2 + 2) >= v.size())) {
7378
              // Invalid triangle.
7379
              // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
7380
119k
              continue;
7381
119k
            }
7382
797
            real_t v0x = v[vi0 * 3 + 0];
7383
797
            real_t v0y = v[vi0 * 3 + 1];
7384
797
            real_t v0z = v[vi0 * 3 + 2];
7385
797
            real_t v1x = v[vi1 * 3 + 0];
7386
797
            real_t v1y = v[vi1 * 3 + 1];
7387
797
            real_t v1z = v[vi1 * 3 + 2];
7388
797
            real_t v2x = v[vi2 * 3 + 0];
7389
797
            real_t v2y = v[vi2 * 3 + 1];
7390
797
            real_t v2z = v[vi2 * 3 + 2];
7391
797
            real_t e0x = v1x - v0x;
7392
797
            real_t e0y = v1y - v0y;
7393
797
            real_t e0z = v1z - v0z;
7394
797
            real_t e1x = v2x - v1x;
7395
797
            real_t e1y = v2y - v1y;
7396
797
            real_t e1z = v2z - v1z;
7397
797
            real_t cx = std::fabs(e0y * e1z - e0z * e1y);
7398
797
            real_t cy = std::fabs(e0z * e1x - e0x * e1z);
7399
797
            real_t cz = std::fabs(e0x * e1y - e0y * e1x);
7400
797
            const real_t epsilon = std::numeric_limits<real_t>::epsilon();
7401
            // std::cout << "cx " << cx << ", cy " << cy << ", cz " << cz <<
7402
            // "\n";
7403
797
            if (cx > epsilon || cy > epsilon || cz > epsilon) {
7404
              // std::cout << "corner\n";
7405
              // found a corner
7406
220
              if (cx > cy && cx > cz) {
7407
                // std::cout << "pattern0\n";
7408
215
              } else {
7409
                // std::cout << "axes[0] = 0\n";
7410
215
                axes[0] = 0;
7411
215
                if (cz > cx && cz > cy) {
7412
                  // std::cout << "axes[1] = 1\n";
7413
55
                  axes[1] = 1;
7414
55
                }
7415
215
              }
7416
220
              break;
7417
220
            }
7418
797
          }
7419
7420
1.45k
          face_t remainingFace = face;  // copy
7421
1.45k
          size_t guess_vert = 0;
7422
1.45k
          vertex_index_t ind[3];
7423
1.45k
          real_t vx[3];
7424
1.45k
          real_t vy[3];
7425
7426
          // How many iterations can we do without decreasing the remaining
7427
          // vertices.
7428
1.45k
          size_t remainingIterations = face.vertex_indices.size();
7429
1.45k
          size_t previousRemainingVertices =
7430
1.45k
              remainingFace.vertex_indices.size();
7431
7432
119k
          while (remainingFace.vertex_indices.size() > 3 &&
7433
118k
                 remainingIterations > 0) {
7434
            // std::cout << "remainingIterations " << remainingIterations <<
7435
            // "\n";
7436
7437
118k
            npolys = remainingFace.vertex_indices.size();
7438
118k
            if (guess_vert >= npolys) {
7439
104
              guess_vert -= npolys;
7440
104
            }
7441
7442
118k
            if (previousRemainingVertices != npolys) {
7443
              // The number of remaining vertices decreased. Reset counters.
7444
115k
              previousRemainingVertices = npolys;
7445
115k
              remainingIterations = npolys;
7446
115k
            } else {
7447
              // We didn't consume a vertex on previous iteration, reduce the
7448
              // available iterations.
7449
2.89k
              remainingIterations--;
7450
2.89k
            }
7451
7452
473k
            for (size_t k = 0; k < 3; k++) {
7453
354k
              ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
7454
354k
              size_t vi = size_t(ind[k].v_idx);
7455
354k
              if (((vi * 3 + axes[0]) >= v.size()) ||
7456
326k
                  ((vi * 3 + axes[1]) >= v.size())) {
7457
                // ???
7458
326k
                vx[k] = static_cast<real_t>(0.0);
7459
326k
                vy[k] = static_cast<real_t>(0.0);
7460
326k
              } else {
7461
28.2k
                vx[k] = v[vi * 3 + axes[0]];
7462
28.2k
                vy[k] = v[vi * 3 + axes[1]];
7463
28.2k
              }
7464
354k
            }
7465
7466
            //
7467
            // area is calculated per face
7468
            //
7469
118k
            real_t e0x = vx[1] - vx[0];
7470
118k
            real_t e0y = vy[1] - vy[0];
7471
118k
            real_t e1x = vx[2] - vx[1];
7472
118k
            real_t e1y = vy[2] - vy[1];
7473
118k
            real_t cross = e0x * e1y - e0y * e1x;
7474
            // std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n";
7475
            // std::cout << "e0x, e0y, e1x, e1y " << e0x << ", " << e0y << ", "
7476
            // << e1x << ", " << e1y << "\n";
7477
7478
118k
            real_t area =
7479
118k
                (vx[0] * vy[1] - vy[0] * vx[1]) * static_cast<real_t>(0.5);
7480
            // std::cout << "cross " << cross << ", area " << area << "\n";
7481
            // if an internal angle
7482
118k
            if (cross * area < static_cast<real_t>(0.0)) {
7483
              // std::cout << "internal \n";
7484
1.16k
              guess_vert += 1;
7485
              // std::cout << "guess vert : " << guess_vert << "\n";
7486
1.16k
              continue;
7487
1.16k
            }
7488
7489
            // check all other verts in case they are inside this triangle
7490
117k
            bool overlap = false;
7491
1.87G
            for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
7492
1.87G
              size_t idx = (guess_vert + otherVert) % npolys;
7493
7494
1.87G
              if (idx >= remainingFace.vertex_indices.size()) {
7495
                // std::cout << "???0\n";
7496
                // ???
7497
0
                continue;
7498
0
              }
7499
7500
1.87G
              size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
7501
7502
1.87G
              if (((ovi * 3 + axes[0]) >= v.size()) ||
7503
1.84G
                  ((ovi * 3 + axes[1]) >= v.size())) {
7504
                // std::cout << "???1\n";
7505
                // ???
7506
1.84G
                continue;
7507
1.84G
              }
7508
25.5M
              real_t tx = v[ovi * 3 + axes[0]];
7509
25.5M
              real_t ty = v[ovi * 3 + axes[1]];
7510
25.5M
              if (pnpoly(3, vx, vy, tx, ty)) {
7511
                // std::cout << "overlap\n";
7512
360
                overlap = true;
7513
360
                break;
7514
360
              }
7515
25.5M
            }
7516
7517
117k
            if (overlap) {
7518
              // std::cout << "overlap2\n";
7519
360
              guess_vert += 1;
7520
360
              continue;
7521
360
            }
7522
7523
            // this triangle is an ear
7524
116k
            {
7525
116k
              index_t idx0, idx1, idx2;
7526
116k
              idx0.vertex_index = ind[0].v_idx;
7527
116k
              idx0.normal_index = ind[0].vn_idx;
7528
116k
              idx0.texcoord_index = ind[0].vt_idx;
7529
116k
              idx1.vertex_index = ind[1].v_idx;
7530
116k
              idx1.normal_index = ind[1].vn_idx;
7531
116k
              idx1.texcoord_index = ind[1].vt_idx;
7532
116k
              idx2.vertex_index = ind[2].v_idx;
7533
116k
              idx2.normal_index = ind[2].vn_idx;
7534
116k
              idx2.texcoord_index = ind[2].vt_idx;
7535
7536
116k
              shape->mesh.indices.push_back(idx0);
7537
116k
              shape->mesh.indices.push_back(idx1);
7538
116k
              shape->mesh.indices.push_back(idx2);
7539
7540
116k
              shape->mesh.num_face_vertices.push_back(3);
7541
116k
              shape->mesh.material_ids.push_back(material_id);
7542
116k
              shape->mesh.smoothing_group_ids.push_back(
7543
116k
                  face.smoothing_group_id);
7544
116k
            }
7545
7546
            // remove v1 from the list
7547
116k
            size_t removed_vert_index = (guess_vert + 1) % npolys;
7548
1.87G
            while (removed_vert_index + 1 < npolys) {
7549
1.87G
              remainingFace.vertex_indices[removed_vert_index] =
7550
1.87G
                  remainingFace.vertex_indices[removed_vert_index + 1];
7551
1.87G
              removed_vert_index += 1;
7552
1.87G
            }
7553
116k
            remainingFace.vertex_indices.pop_back();
7554
116k
          }
7555
7556
          // std::cout << "remainingFace.vi.size = " <<
7557
          // remainingFace.vertex_indices.size() << "\n";
7558
1.45k
          if (remainingFace.vertex_indices.size() == 3) {
7559
1.37k
            i0 = remainingFace.vertex_indices[0];
7560
1.37k
            i1 = remainingFace.vertex_indices[1];
7561
1.37k
            i2 = remainingFace.vertex_indices[2];
7562
1.37k
            {
7563
1.37k
              index_t idx0, idx1, idx2;
7564
1.37k
              idx0.vertex_index = i0.v_idx;
7565
1.37k
              idx0.normal_index = i0.vn_idx;
7566
1.37k
              idx0.texcoord_index = i0.vt_idx;
7567
1.37k
              idx1.vertex_index = i1.v_idx;
7568
1.37k
              idx1.normal_index = i1.vn_idx;
7569
1.37k
              idx1.texcoord_index = i1.vt_idx;
7570
1.37k
              idx2.vertex_index = i2.v_idx;
7571
1.37k
              idx2.normal_index = i2.vn_idx;
7572
1.37k
              idx2.texcoord_index = i2.vt_idx;
7573
7574
1.37k
              shape->mesh.indices.push_back(idx0);
7575
1.37k
              shape->mesh.indices.push_back(idx1);
7576
1.37k
              shape->mesh.indices.push_back(idx2);
7577
7578
1.37k
              shape->mesh.num_face_vertices.push_back(3);
7579
1.37k
              shape->mesh.material_ids.push_back(material_id);
7580
1.37k
              shape->mesh.smoothing_group_ids.push_back(
7581
1.37k
                  face.smoothing_group_id);
7582
1.37k
            }
7583
1.37k
          }
7584
1.45k
#endif
7585
1.45k
        }  // npolys
7586
3.43k
      } else {
7587
5.12k
        for (size_t k = 0; k < npolys; k++) {
7588
3.84k
          index_t idx;
7589
3.84k
          idx.vertex_index = face.vertex_indices[k].v_idx;
7590
3.84k
          idx.normal_index = face.vertex_indices[k].vn_idx;
7591
3.84k
          idx.texcoord_index = face.vertex_indices[k].vt_idx;
7592
3.84k
          shape->mesh.indices.push_back(idx);
7593
3.84k
        }
7594
7595
1.28k
        shape->mesh.num_face_vertices.push_back(
7596
1.28k
            static_cast<unsigned int>(npolys));
7597
1.28k
        shape->mesh.material_ids.push_back(material_id);  // per face
7598
1.28k
        shape->mesh.smoothing_group_ids.push_back(
7599
1.28k
            face.smoothing_group_id);  // per face
7600
1.28k
      }
7601
4.71k
    }
7602
7603
3.10k
    shape->mesh.tags = tags;
7604
3.10k
  }
7605
7606
  // line
7607
9.52k
  if (!prim_group.lineGroup.empty()) {
7608
    // Flatten indices
7609
196k
    for (size_t i = 0; i < prim_group.lineGroup.size(); i++) {
7610
197k
      for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size();
7611
194k
           j++) {
7612
2.91k
        const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j];
7613
7614
2.91k
        index_t idx;
7615
2.91k
        idx.vertex_index = vi.v_idx;
7616
2.91k
        idx.normal_index = vi.vn_idx;
7617
2.91k
        idx.texcoord_index = vi.vt_idx;
7618
7619
2.91k
        shape->lines.indices.push_back(idx);
7620
2.91k
      }
7621
7622
194k
      shape->lines.num_line_vertices.push_back(
7623
194k
          int(prim_group.lineGroup[i].vertex_indices.size()));
7624
194k
    }
7625
1.44k
  }
7626
7627
  // points
7628
9.52k
  if (!prim_group.pointsGroup.empty()) {
7629
    // Flatten & convert indices
7630
14.4k
    for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) {
7631
44.3k
      for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size();
7632
35.5k
           j++) {
7633
35.5k
        const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j];
7634
7635
35.5k
        index_t idx;
7636
35.5k
        idx.vertex_index = vi.v_idx;
7637
35.5k
        idx.normal_index = vi.vn_idx;
7638
35.5k
        idx.texcoord_index = vi.vt_idx;
7639
7640
35.5k
        shape->points.indices.push_back(idx);
7641
35.5k
      }
7642
8.80k
    }
7643
5.66k
  }
7644
7645
9.52k
  return true;
7646
19.7k
}
7647
7648
// Split a string with specified delimiter character and escape character.
7649
// https://rosettacode.org/wiki/Tokenize_a_string_with_escaping#C.2B.2B
7650
static void SplitString(const std::string &s, char delim, char escape,
7651
8.25k
                        std::vector<std::string> &elems) {
7652
8.25k
  std::string token;
7653
7654
8.25k
  bool escaping = false;
7655
18.0M
  for (size_t i = 0; i < s.size(); ++i) {
7656
18.0M
    char ch = s[i];
7657
18.0M
    if (escaping) {
7658
19.3k
      escaping = false;
7659
18.0M
    } else if (ch == escape) {
7660
19.5k
      if ((i + 1) < s.size()) {
7661
19.4k
        const char next = s[i + 1];
7662
19.4k
        if ((next == delim) || (next == escape)) {
7663
19.3k
          escaping = true;
7664
19.3k
          continue;
7665
19.3k
        }
7666
19.4k
      }
7667
18.0M
    } else if (ch == delim) {
7668
28.7k
      if (!token.empty()) {
7669
27.7k
        elems.push_back(token);
7670
27.7k
      }
7671
28.7k
      token.clear();
7672
28.7k
      continue;
7673
28.7k
    }
7674
18.0M
    token += ch;
7675
18.0M
  }
7676
7677
8.25k
  elems.push_back(token);
7678
8.25k
}
7679
7680
8.25k
static void RemoveEmptyTokens(std::vector<std::string> *tokens) {
7681
8.25k
  if (!tokens) return;
7682
7683
8.25k
  const std::vector<std::string> &src = *tokens;
7684
8.25k
  std::vector<std::string> filtered;
7685
8.25k
  filtered.reserve(src.size());
7686
44.2k
  for (size_t i = 0; i < src.size(); i++) {
7687
36.0k
    if (!src[i].empty()) {
7688
30.5k
      filtered.push_back(src[i]);
7689
30.5k
    }
7690
36.0k
  }
7691
8.25k
  tokens->swap(filtered);
7692
8.25k
}
7693
7694
static std::string JoinPath(const std::string &dir,
7695
0
                            const std::string &filename) {
7696
0
  if (dir.empty()) {
7697
0
    return filename;
7698
0
  } else {
7699
    // check '/'
7700
0
    char lastChar = *dir.rbegin();
7701
0
    if (lastChar != '/') {
7702
0
      return dir + std::string("/") + filename;
7703
0
    } else {
7704
0
      return dir + filename;
7705
0
    }
7706
0
  }
7707
0
}
7708
7709
static bool LoadMtlInternal(std::map<std::string, int> *material_map,
7710
                            std::vector<material_t> *materials,
7711
                            StreamReader &sr,
7712
                            std::string *warning, std::string *err,
7713
1.60k
                            const std::string &filename = "<stream>") {
7714
1.60k
  if (sr.has_errors()) {
7715
0
    if (err) {
7716
0
      (*err) += sr.get_errors();
7717
0
    }
7718
0
    return false;
7719
0
  }
7720
7721
1.60k
  material_t material;
7722
1.60k
  InitMaterial(&material);
7723
7724
  // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification.
7725
1.60k
  bool has_d = false;
7726
1.60k
  bool has_tr = false;
7727
7728
  // has_kd is used to set a default diffuse value when map_Kd is present
7729
  // and Kd is not.
7730
1.60k
  bool has_kd = false;
7731
7732
1.60k
  std::stringstream warn_ss;
7733
7734
  // Handle BOM
7735
1.60k
  if (sr.remaining() >= 3 &&
7736
756
      static_cast<unsigned char>(sr.peek()) == 0xEF &&
7737
7
      static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
7738
7
      static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
7739
7
    sr.advance(3);
7740
7
  }
7741
7742
207k
  while (!sr.eof()) {
7743
205k
    sr.skip_space();
7744
205k
    if (sr.at_line_end()) { sr.skip_line(); continue; }
7745
165k
    if (sr.peek() == '#') { sr.skip_line(); continue; }
7746
7747
165k
    size_t line_num = sr.line_num();
7748
7749
    // new mtl
7750
165k
    if (sr.match("newmtl", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7751
      // flush previous material.
7752
41.2k
      if (!material.name.empty()) {
7753
40.9k
        material_map->insert(std::pair<std::string, int>(
7754
40.9k
            material.name, static_cast<int>(materials->size())));
7755
40.9k
        materials->push_back(material);
7756
40.9k
      }
7757
7758
41.2k
      InitMaterial(&material);
7759
7760
41.2k
      has_d = false;
7761
41.2k
      has_tr = false;
7762
41.2k
      has_kd = false;
7763
7764
41.2k
      sr.advance(7);
7765
41.2k
      {
7766
41.2k
        std::string namebuf = sr_parseString(sr);
7767
41.2k
        if (namebuf.empty()) {
7768
98
          if (warning) {
7769
98
            (*warning) += "empty material name in `newmtl`\n";
7770
98
          }
7771
98
        }
7772
41.2k
        material.name = namebuf;
7773
41.2k
      }
7774
41.2k
      sr.skip_line();
7775
41.2k
      continue;
7776
41.2k
    }
7777
7778
    // ambient
7779
124k
    if (sr.peek() == 'K' && sr.peek_at(1) == 'a' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7780
6
      sr.advance(2);
7781
6
      real_t r, g, b;
7782
6
      if (!sr_parseReal3(&r, &g, &b, sr, err, filename)) return false;
7783
1
      material.ambient[0] = r;
7784
1
      material.ambient[1] = g;
7785
1
      material.ambient[2] = b;
7786
1
      sr.skip_line();
7787
1
      continue;
7788
6
    }
7789
7790
    // diffuse
7791
124k
    if (sr.peek() == 'K' && sr.peek_at(1) == 'd' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7792
6
      sr.advance(2);
7793
6
      real_t r, g, b;
7794
6
      if (!sr_parseReal3(&r, &g, &b, sr, err, filename)) return false;
7795
1
      material.diffuse[0] = r;
7796
1
      material.diffuse[1] = g;
7797
1
      material.diffuse[2] = b;
7798
1
      has_kd = true;
7799
1
      sr.skip_line();
7800
1
      continue;
7801
6
    }
7802
7803
    // specular
7804
124k
    if (sr.peek() == 'K' && sr.peek_at(1) == 's' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7805
4
      sr.advance(2);
7806
4
      real_t r, g, b;
7807
4
      if (!sr_parseReal3(&r, &g, &b, sr, err, filename)) return false;
7808
0
      material.specular[0] = r;
7809
0
      material.specular[1] = g;
7810
0
      material.specular[2] = b;
7811
0
      sr.skip_line();
7812
0
      continue;
7813
4
    }
7814
7815
    // transmittance
7816
124k
    if ((sr.peek() == 'K' && sr.peek_at(1) == 't' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) ||
7817
124k
        (sr.peek() == 'T' && sr.peek_at(1) == 'f' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t'))) {
7818
10
      sr.advance(2);
7819
10
      real_t r, g, b;
7820
10
      if (!sr_parseReal3(&r, &g, &b, sr, err, filename)) return false;
7821
2
      material.transmittance[0] = r;
7822
2
      material.transmittance[1] = g;
7823
2
      material.transmittance[2] = b;
7824
2
      sr.skip_line();
7825
2
      continue;
7826
10
    }
7827
7828
    // ior(index of refraction)
7829
124k
    if (sr.peek() == 'N' && sr.peek_at(1) == 'i' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7830
3
      sr.advance(2);
7831
3
      if (!sr_parseReal(sr, &material.ior, 0.0, err, filename)) return false;
7832
0
      sr.skip_line();
7833
0
      continue;
7834
3
    }
7835
7836
    // emission
7837
124k
    if (sr.peek() == 'K' && sr.peek_at(1) == 'e' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7838
14
      sr.advance(2);
7839
14
      real_t r, g, b;
7840
14
      if (!sr_parseReal3(&r, &g, &b, sr, err, filename)) return false;
7841
11
      material.emission[0] = r;
7842
11
      material.emission[1] = g;
7843
11
      material.emission[2] = b;
7844
11
      sr.skip_line();
7845
11
      continue;
7846
14
    }
7847
7848
    // shininess
7849
124k
    if (sr.peek() == 'N' && sr.peek_at(1) == 's' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7850
6
      sr.advance(2);
7851
6
      if (!sr_parseReal(sr, &material.shininess, 0.0, err, filename)) return false;
7852
0
      sr.skip_line();
7853
0
      continue;
7854
6
    }
7855
7856
    // illum model
7857
124k
    if (sr.match("illum", 5) && (sr.peek_at(5) == ' ' || sr.peek_at(5) == '\t')) {
7858
6
      sr.advance(6);
7859
6
      if (!sr_parseInt(sr, &material.illum, err, filename)) return false;
7860
0
      sr.skip_line();
7861
0
      continue;
7862
6
    }
7863
7864
    // dissolve
7865
124k
    if (sr.peek() == 'd' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
7866
18
      sr.advance(1);
7867
18
      if (!sr_parseReal(sr, &material.dissolve, 0.0, err, filename)) return false;
7868
7869
4
      if (has_tr) {
7870
0
        warn_ss << "Both `d` and `Tr` parameters defined for \""
7871
0
                << material.name
7872
0
                << "\". Use the value of `d` for dissolve (line " << line_num
7873
0
                << " in .mtl.)\n";
7874
0
      }
7875
4
      has_d = true;
7876
4
      sr.skip_line();
7877
4
      continue;
7878
18
    }
7879
124k
    if (sr.peek() == 'T' && sr.peek_at(1) == 'r' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7880
7
      sr.advance(2);
7881
7
      if (has_d) {
7882
0
        warn_ss << "Both `d` and `Tr` parameters defined for \""
7883
0
                << material.name
7884
0
                << "\". Use the value of `d` for dissolve (line " << line_num
7885
0
                << " in .mtl.)\n";
7886
7
      } else {
7887
7
        real_t tr_val;
7888
7
        if (!sr_parseReal(sr, &tr_val, 0.0, err, filename)) return false;
7889
1
        material.dissolve = static_cast<real_t>(1.0) - tr_val;
7890
1
      }
7891
1
      has_tr = true;
7892
1
      sr.skip_line();
7893
1
      continue;
7894
7
    }
7895
7896
    // PBR: roughness
7897
124k
    if (sr.peek() == 'P' && sr.peek_at(1) == 'r' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7898
6
      sr.advance(2);
7899
6
      if (!sr_parseReal(sr, &material.roughness, 0.0, err, filename)) return false;
7900
0
      sr.skip_line();
7901
0
      continue;
7902
6
    }
7903
7904
    // PBR: metallic
7905
124k
    if (sr.peek() == 'P' && sr.peek_at(1) == 'm' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7906
4
      sr.advance(2);
7907
4
      if (!sr_parseReal(sr, &material.metallic, 0.0, err, filename)) return false;
7908
0
      sr.skip_line();
7909
0
      continue;
7910
4
    }
7911
7912
    // PBR: sheen
7913
124k
    if (sr.peek() == 'P' && sr.peek_at(1) == 's' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7914
21
      sr.advance(2);
7915
21
      if (!sr_parseReal(sr, &material.sheen, 0.0, err, filename)) return false;
7916
15
      sr.skip_line();
7917
15
      continue;
7918
21
    }
7919
7920
    // PBR: clearcoat thickness
7921
124k
    if (sr.peek() == 'P' && sr.peek_at(1) == 'c' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
7922
2
      sr.advance(2);
7923
2
      if (!sr_parseReal(sr, &material.clearcoat_thickness, 0.0, err, filename)) return false;
7924
0
      sr.skip_line();
7925
0
      continue;
7926
2
    }
7927
7928
    // PBR: clearcoat roughness
7929
124k
    if (sr.match("Pcr", 3) && (sr.peek_at(3) == ' ' || sr.peek_at(3) == '\t')) {
7930
6
      sr.advance(4);
7931
6
      if (!sr_parseReal(sr, &material.clearcoat_roughness, 0.0, err, filename)) return false;
7932
3
      sr.skip_line();
7933
3
      continue;
7934
6
    }
7935
7936
    // PBR: anisotropy
7937
124k
    if (sr.match("aniso", 5) && (sr.peek_at(5) == ' ' || sr.peek_at(5) == '\t')) {
7938
4
      sr.advance(6);
7939
4
      if (!sr_parseReal(sr, &material.anisotropy, 0.0, err, filename)) return false;
7940
0
      sr.skip_line();
7941
0
      continue;
7942
4
    }
7943
7944
    // PBR: anisotropy rotation
7945
124k
    if (sr.match("anisor", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7946
5
      sr.advance(7);
7947
5
      if (!sr_parseReal(sr, &material.anisotropy_rotation, 0.0, err, filename)) return false;
7948
0
      sr.skip_line();
7949
0
      continue;
7950
5
    }
7951
7952
    // For texture directives, read rest of line and delegate to
7953
    // ParseTextureNameAndOption (which uses the old const char* parse functions).
7954
7955
    // ambient or ambient occlusion texture
7956
124k
    if (sr.match("map_Ka", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7957
52
      sr.advance(7);
7958
52
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
7959
52
      ParseTextureNameAndOption(&(material.ambient_texname),
7960
52
                                &(material.ambient_texopt), line_rest.c_str());
7961
52
      sr.skip_line();
7962
52
      continue;
7963
52
    }
7964
7965
    // diffuse texture
7966
124k
    if (sr.match("map_Kd", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7967
770
      sr.advance(7);
7968
770
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
7969
770
      ParseTextureNameAndOption(&(material.diffuse_texname),
7970
770
                                &(material.diffuse_texopt), line_rest.c_str());
7971
770
      if (!has_kd) {
7972
769
        material.diffuse[0] = static_cast<real_t>(0.6);
7973
769
        material.diffuse[1] = static_cast<real_t>(0.6);
7974
769
        material.diffuse[2] = static_cast<real_t>(0.6);
7975
769
      }
7976
770
      sr.skip_line();
7977
770
      continue;
7978
770
    }
7979
7980
    // specular texture
7981
123k
    if (sr.match("map_Ks", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7982
294
      sr.advance(7);
7983
294
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
7984
294
      ParseTextureNameAndOption(&(material.specular_texname),
7985
294
                                &(material.specular_texopt), line_rest.c_str());
7986
294
      sr.skip_line();
7987
294
      continue;
7988
294
    }
7989
7990
    // specular highlight texture
7991
123k
    if (sr.match("map_Ns", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
7992
36
      sr.advance(7);
7993
36
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
7994
36
      ParseTextureNameAndOption(&(material.specular_highlight_texname),
7995
36
                                &(material.specular_highlight_texopt), line_rest.c_str());
7996
36
      sr.skip_line();
7997
36
      continue;
7998
36
    }
7999
8000
    // bump texture
8001
122k
    if ((sr.match("map_bump", 8) || sr.match("map_Bump", 8)) &&
8002
474
        (sr.peek_at(8) == ' ' || sr.peek_at(8) == '\t')) {
8003
179
      sr.advance(9);
8004
179
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8005
179
      ParseTextureNameAndOption(&(material.bump_texname),
8006
179
                                &(material.bump_texopt), line_rest.c_str());
8007
179
      sr.skip_line();
8008
179
      continue;
8009
179
    }
8010
8011
    // bump texture (short form)
8012
122k
    if (sr.match("bump", 4) && (sr.peek_at(4) == ' ' || sr.peek_at(4) == '\t')) {
8013
463
      sr.advance(5);
8014
463
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8015
463
      ParseTextureNameAndOption(&(material.bump_texname),
8016
463
                                &(material.bump_texopt), line_rest.c_str());
8017
463
      sr.skip_line();
8018
463
      continue;
8019
463
    }
8020
8021
    // alpha texture
8022
122k
    if (sr.match("map_d", 5) && (sr.peek_at(5) == ' ' || sr.peek_at(5) == '\t')) {
8023
369
      sr.advance(6);
8024
369
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8025
369
      ParseTextureNameAndOption(&(material.alpha_texname),
8026
369
                                &(material.alpha_texopt), line_rest.c_str());
8027
369
      sr.skip_line();
8028
369
      continue;
8029
369
    }
8030
8031
    // displacement texture
8032
121k
    if ((sr.match("map_disp", 8) || sr.match("map_Disp", 8)) &&
8033
300
        (sr.peek_at(8) == ' ' || sr.peek_at(8) == '\t')) {
8034
237
      sr.advance(9);
8035
237
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8036
237
      ParseTextureNameAndOption(&(material.displacement_texname),
8037
237
                                &(material.displacement_texopt), line_rest.c_str());
8038
237
      sr.skip_line();
8039
237
      continue;
8040
237
    }
8041
8042
    // displacement texture (short form)
8043
121k
    if (sr.match("disp", 4) && (sr.peek_at(4) == ' ' || sr.peek_at(4) == '\t')) {
8044
539
      sr.advance(5);
8045
539
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8046
539
      ParseTextureNameAndOption(&(material.displacement_texname),
8047
539
                                &(material.displacement_texopt), line_rest.c_str());
8048
539
      sr.skip_line();
8049
539
      continue;
8050
539
    }
8051
8052
    // reflection map
8053
121k
    if (sr.match("refl", 4) && (sr.peek_at(4) == ' ' || sr.peek_at(4) == '\t')) {
8054
795
      sr.advance(5);
8055
795
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8056
795
      ParseTextureNameAndOption(&(material.reflection_texname),
8057
795
                                &(material.reflection_texopt), line_rest.c_str());
8058
795
      sr.skip_line();
8059
795
      continue;
8060
795
    }
8061
8062
    // PBR: roughness texture
8063
120k
    if (sr.match("map_Pr", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8064
390
      sr.advance(7);
8065
390
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8066
390
      ParseTextureNameAndOption(&(material.roughness_texname),
8067
390
                                &(material.roughness_texopt), line_rest.c_str());
8068
390
      sr.skip_line();
8069
390
      continue;
8070
390
    }
8071
8072
    // PBR: metallic texture
8073
120k
    if (sr.match("map_Pm", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8074
17
      sr.advance(7);
8075
17
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8076
17
      ParseTextureNameAndOption(&(material.metallic_texname),
8077
17
                                &(material.metallic_texopt), line_rest.c_str());
8078
17
      sr.skip_line();
8079
17
      continue;
8080
17
    }
8081
8082
    // PBR: sheen texture
8083
120k
    if (sr.match("map_Ps", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8084
64
      sr.advance(7);
8085
64
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8086
64
      ParseTextureNameAndOption(&(material.sheen_texname),
8087
64
                                &(material.sheen_texopt), line_rest.c_str());
8088
64
      sr.skip_line();
8089
64
      continue;
8090
64
    }
8091
8092
    // PBR: emissive texture
8093
119k
    if (sr.match("map_Ke", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8094
64
      sr.advance(7);
8095
64
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8096
64
      ParseTextureNameAndOption(&(material.emissive_texname),
8097
64
                                &(material.emissive_texopt), line_rest.c_str());
8098
64
      sr.skip_line();
8099
64
      continue;
8100
64
    }
8101
8102
    // PBR: normal map texture
8103
119k
    if (sr.match("norm", 4) && (sr.peek_at(4) == ' ' || sr.peek_at(4) == '\t')) {
8104
634
      sr.advance(5);
8105
634
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8106
634
      ParseTextureNameAndOption(&(material.normal_texname),
8107
634
                                &(material.normal_texopt), line_rest.c_str());
8108
634
      sr.skip_line();
8109
634
      continue;
8110
634
    }
8111
8112
    // unknown parameter
8113
119k
    {
8114
119k
      std::string line_rest = trimTrailingWhitespace(sr.read_line());
8115
119k
      const char *_lp = line_rest.c_str();
8116
119k
      const char *_space = strchr(_lp, ' ');
8117
119k
      if (!_space) {
8118
112k
        _space = strchr(_lp, '\t');
8119
112k
      }
8120
119k
      if (_space) {
8121
10.7k
        std::ptrdiff_t len = _space - _lp;
8122
10.7k
        std::string key(_lp, static_cast<size_t>(len));
8123
10.7k
        std::string value = _space + 1;
8124
10.7k
        material.unknown_parameter.insert(
8125
10.7k
            std::pair<std::string, std::string>(key, value));
8126
10.7k
      }
8127
119k
    }
8128
119k
    sr.skip_line();
8129
119k
  }
8130
  // flush last material (only if it was actually defined).
8131
1.51k
  if (!material.name.empty()) {
8132
164
    material_map->insert(std::pair<std::string, int>(
8133
164
        material.name, static_cast<int>(materials->size())));
8134
164
    materials->push_back(material);
8135
164
  }
8136
8137
1.51k
  if (warning) {
8138
1.51k
    (*warning) += warn_ss.str();
8139
1.51k
  }
8140
8141
1.51k
  return true;
8142
1.60k
}
8143
8144
void LoadMtl(std::map<std::string, int> *material_map,
8145
             std::vector<material_t> *materials, std::istream *inStream,
8146
0
             std::string *warning, std::string *err) {
8147
0
  StreamReader sr(*inStream);
8148
0
  LoadMtlInternal(material_map, materials, sr, warning, err);
8149
0
}
8150
8151
8152
bool MaterialFileReader::operator()(const std::string &matId,
8153
                                    std::vector<material_t> *materials,
8154
                                    std::map<std::string, int> *matMap,
8155
0
                                    std::string *warn, std::string *err) {
8156
0
  if (!m_mtlBaseDir.empty()) {
8157
#ifdef _WIN32
8158
    char sep = ';';
8159
#else
8160
0
    char sep = ':';
8161
0
#endif
8162
8163
    // https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g
8164
0
    std::vector<std::string> paths;
8165
0
    std::istringstream f(m_mtlBaseDir);
8166
8167
0
    std::string s;
8168
0
    while (getline(f, s, sep)) {
8169
0
      paths.push_back(s);
8170
0
    }
8171
8172
0
    for (size_t i = 0; i < paths.size(); i++) {
8173
0
      std::string filepath = JoinPath(paths[i], matId);
8174
8175
#ifdef TINYOBJLOADER_USE_MMAP
8176
      {
8177
        MappedFile mf;
8178
        if (!mf.open(filepath.c_str())) continue;
8179
        if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8180
          if (err) {
8181
            std::stringstream ss;
8182
            ss << "input stream too large (" << mf.size
8183
               << " bytes exceeds limit "
8184
               << TINYOBJLOADER_STREAM_READER_MAX_BYTES << " bytes)\n";
8185
            (*err) += ss.str();
8186
          }
8187
          return false;
8188
        }
8189
        StreamReader sr(mf.data, mf.size);
8190
        return LoadMtlInternal(matMap, materials, sr, warn, err, filepath);
8191
      }
8192
#else   // !TINYOBJLOADER_USE_MMAP
8193
#ifdef _WIN32
8194
      std::ifstream matIStream(LongPathW(UTF8ToWchar(filepath)).c_str());
8195
#else
8196
0
      std::ifstream matIStream(filepath.c_str());
8197
0
#endif
8198
0
      if (matIStream) {
8199
0
        StreamReader mtl_sr(matIStream);
8200
0
        return LoadMtlInternal(matMap, materials, mtl_sr, warn, err, filepath);
8201
0
      }
8202
0
#endif  // TINYOBJLOADER_USE_MMAP
8203
0
    }
8204
8205
0
    std::stringstream ss;
8206
0
    ss << "Material file [ " << matId
8207
0
       << " ] not found in a path : " << m_mtlBaseDir << "\n";
8208
0
    if (warn) {
8209
0
      (*warn) += ss.str();
8210
0
    }
8211
0
    return false;
8212
8213
0
  } else {
8214
0
    std::string filepath = matId;
8215
8216
#ifdef TINYOBJLOADER_USE_MMAP
8217
    {
8218
      MappedFile mf;
8219
      if (mf.open(filepath.c_str())) {
8220
        if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8221
          if (err) {
8222
            std::stringstream ss;
8223
            ss << "input stream too large (" << mf.size
8224
               << " bytes exceeds limit "
8225
               << TINYOBJLOADER_STREAM_READER_MAX_BYTES << " bytes)\n";
8226
            (*err) += ss.str();
8227
          }
8228
          return false;
8229
        }
8230
        StreamReader sr(mf.data, mf.size);
8231
        return LoadMtlInternal(matMap, materials, sr, warn, err, filepath);
8232
      }
8233
    }
8234
#else   // !TINYOBJLOADER_USE_MMAP
8235
#ifdef _WIN32
8236
    std::ifstream matIStream(LongPathW(UTF8ToWchar(filepath)).c_str());
8237
#else
8238
0
    std::ifstream matIStream(filepath.c_str());
8239
0
#endif
8240
0
    if (matIStream) {
8241
0
      StreamReader mtl_sr(matIStream);
8242
0
      return LoadMtlInternal(matMap, materials, mtl_sr, warn, err, filepath);
8243
0
    }
8244
0
#endif  // TINYOBJLOADER_USE_MMAP
8245
8246
0
    std::stringstream ss;
8247
0
    ss << "Material file [ " << filepath
8248
0
       << " ] not found in a path : " << m_mtlBaseDir << "\n";
8249
0
    if (warn) {
8250
0
      (*warn) += ss.str();
8251
0
    }
8252
8253
0
    return false;
8254
0
  }
8255
0
}
8256
8257
bool MaterialStreamReader::operator()(const std::string &matId,
8258
                                      std::vector<material_t> *materials,
8259
                                      std::map<std::string, int> *matMap,
8260
1.60k
                                      std::string *warn, std::string *err) {
8261
1.60k
  (void)matId;
8262
1.60k
  if (!m_inStream) {
8263
0
    std::stringstream ss;
8264
0
    ss << "Material stream in error state. \n";
8265
0
    if (warn) {
8266
0
      (*warn) += ss.str();
8267
0
    }
8268
0
    return false;
8269
0
  }
8270
8271
1.60k
  StreamReader mtl_sr(m_inStream);
8272
1.60k
  return LoadMtlInternal(matMap, materials, mtl_sr, warn, err, "<stream>");
8273
1.60k
}
8274
8275
static bool LoadObjInternal(attrib_t *attrib, std::vector<shape_t> *shapes,
8276
                            std::vector<material_t> *materials,
8277
                            std::string *warn, std::string *err,
8278
                            StreamReader &sr,
8279
                            MaterialReader *readMatFn, bool triangulate,
8280
                            bool default_vcols_fallback,
8281
8.54k
                            const std::string &filename = "<stream>") {
8282
8.54k
  if (sr.has_errors()) {
8283
0
    if (err) {
8284
0
      (*err) += sr.get_errors();
8285
0
    }
8286
0
    return false;
8287
0
  }
8288
8289
8.54k
  std::vector<real_t> v;
8290
8.54k
  std::vector<real_t> vertex_weights;
8291
8.54k
  std::vector<real_t> vn;
8292
8.54k
  std::vector<real_t> vt;
8293
8.54k
  std::vector<real_t> vt_w;  // optional [w] component in `vt`
8294
8.54k
  std::vector<real_t> vc;
8295
8.54k
  std::vector<skin_weight_t> vw;
8296
8.54k
  std::vector<tag_t> tags;
8297
8.54k
  PrimGroup prim_group;
8298
8.54k
  std::string name;
8299
8300
  // material
8301
8.54k
  std::set<std::string> material_filenames;
8302
8.54k
  std::map<std::string, int> material_map;
8303
8.54k
  int material = -1;
8304
8305
8.54k
  unsigned int current_smoothing_id = 0;
8306
8307
8.54k
  int greatest_v_idx = -1;
8308
8.54k
  int greatest_vn_idx = -1;
8309
8.54k
  int greatest_vt_idx = -1;
8310
8311
8.54k
  shape_t shape;
8312
8313
8.54k
  bool found_all_colors = true;
8314
8315
  // Handle BOM
8316
8.54k
  if (sr.remaining() >= 3 &&
8317
8.31k
      static_cast<unsigned char>(sr.peek()) == 0xEF &&
8318
107
      static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
8319
93
      static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
8320
78
    sr.advance(3);
8321
78
  }
8322
8323
8.54k
  warning_context context;
8324
8.54k
  context.warn = warn;
8325
8.54k
  context.filename = filename;
8326
8327
1.69M
  while (!sr.eof()) {
8328
1.68M
    sr.skip_space();
8329
1.68M
    if (sr.at_line_end()) { sr.skip_line(); continue; }
8330
1.60M
    if (sr.peek() == '#') { sr.skip_line(); continue; }
8331
8332
1.60M
    size_t line_num = sr.line_num();
8333
8334
    // vertex
8335
1.60M
    if (sr.peek() == 'v' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8336
3.39k
      sr.advance(2);
8337
3.39k
      real_t x, y, z;
8338
3.39k
      real_t r, g, b;
8339
8340
3.39k
      int num_components = sr_parseVertexWithColor(&x, &y, &z, &r, &g, &b, sr, err, filename);
8341
3.39k
      if (num_components < 0) return false;
8342
3.00k
      found_all_colors &= (num_components == 6);
8343
8344
3.00k
      v.push_back(x);
8345
3.00k
      v.push_back(y);
8346
3.00k
      v.push_back(z);
8347
8348
3.00k
      vertex_weights.push_back(r);
8349
8350
3.00k
      if ((num_components == 6) || default_vcols_fallback) {
8351
3.00k
        vc.push_back(r);
8352
3.00k
        vc.push_back(g);
8353
3.00k
        vc.push_back(b);
8354
3.00k
      }
8355
8356
3.00k
      sr.skip_line();
8357
3.00k
      continue;
8358
3.39k
    }
8359
8360
    // normal
8361
1.59M
    if (sr.peek() == 'v' && sr.peek_at(1) == 'n' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
8362
921
      sr.advance(3);
8363
921
      real_t x, y, z;
8364
921
      if (!sr_parseReal3(&x, &y, &z, sr, err, filename)) return false;
8365
911
      vn.push_back(x);
8366
911
      vn.push_back(y);
8367
911
      vn.push_back(z);
8368
911
      sr.skip_line();
8369
911
      continue;
8370
921
    }
8371
8372
    // texcoord
8373
1.59M
    if (sr.peek() == 'v' && sr.peek_at(1) == 't' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
8374
1.05k
      sr.advance(3);
8375
1.05k
      real_t x, y;
8376
1.05k
      if (!sr_parseReal2(&x, &y, sr, err, filename)) return false;
8377
1.05k
      vt.push_back(x);
8378
1.05k
      vt.push_back(y);
8379
8380
      // Parse optional w component
8381
1.05k
      real_t w = static_cast<real_t>(0.0);
8382
1.05k
      sr_parseReal(sr, &w);
8383
1.05k
      vt_w.push_back(w);
8384
8385
1.05k
      sr.skip_line();
8386
1.05k
      continue;
8387
1.05k
    }
8388
8389
    // skin weight. tinyobj extension
8390
1.59M
    if (sr.peek() == 'v' && sr.peek_at(1) == 'w' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
8391
164
      sr.advance(3);
8392
8393
164
      int vid;
8394
164
      if (!sr_parseInt(sr, &vid, err, filename)) return false;
8395
8396
12
      skin_weight_t sw;
8397
12
      sw.vertex_id = vid;
8398
8399
12
      size_t vw_loop_max = sr.remaining() + 1;
8400
12
      size_t vw_loop_iter = 0;
8401
145
      while (!sr.at_line_end() && sr.peek() != '#' &&
8402
136
             vw_loop_iter < vw_loop_max) {
8403
136
        real_t j, w;
8404
136
        sr_parseReal2(&j, &w, sr, -1.0);
8405
8406
136
        if (j < static_cast<real_t>(0)) {
8407
3
          if (err) {
8408
3
            (*err) += sr.format_error(filename,
8409
3
                "failed to parse `vw' line: joint_id is negative");
8410
3
          }
8411
3
          return false;
8412
3
        }
8413
8414
133
        joint_and_weight_t jw;
8415
133
        jw.joint_id = int(j);
8416
133
        jw.weight = w;
8417
8418
133
        sw.weightValues.push_back(jw);
8419
133
        sr.skip_space_and_cr();
8420
133
        vw_loop_iter++;
8421
133
      }
8422
8423
9
      vw.push_back(sw);
8424
9
      sr.skip_line();
8425
9
      continue;
8426
12
    }
8427
8428
1.59M
    context.line_number = line_num;
8429
8430
    // line
8431
1.59M
    if (sr.peek() == 'l' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8432
255k
      sr.advance(2);
8433
8434
255k
      __line_t line;
8435
8436
255k
      size_t l_loop_max = sr.remaining() + 1;
8437
255k
      size_t l_loop_iter = 0;
8438
259k
      while (!sr.at_line_end() && sr.peek() != '#' &&
8439
4.21k
             l_loop_iter < l_loop_max) {
8440
4.21k
        vertex_index_t vi;
8441
4.21k
        if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8442
4.21k
                         size_to_int(vn.size() / 3),
8443
4.21k
                         size_to_int(vt.size() / 2), &vi, context)) {
8444
70
          if (err) {
8445
70
            (*err) += sr.format_error(filename,
8446
70
                "failed to parse `l' line (invalid vertex index)");
8447
70
          }
8448
70
          return false;
8449
70
        }
8450
8451
4.14k
        line.vertex_indices.push_back(vi);
8452
4.14k
        sr.skip_space_and_cr();
8453
4.14k
        l_loop_iter++;
8454
4.14k
      }
8455
8456
255k
      prim_group.lineGroup.push_back(line);
8457
255k
      sr.skip_line();
8458
255k
      continue;
8459
255k
    }
8460
8461
    // points
8462
1.33M
    if (sr.peek() == 'p' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8463
183k
      sr.advance(2);
8464
8465
183k
      __points_t pts;
8466
8467
183k
      size_t p_loop_max = sr.remaining() + 1;
8468
183k
      size_t p_loop_iter = 0;
8469
224k
      while (!sr.at_line_end() && sr.peek() != '#' &&
8470
40.6k
             p_loop_iter < p_loop_max) {
8471
40.6k
        vertex_index_t vi;
8472
40.6k
        if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8473
40.6k
                         size_to_int(vn.size() / 3),
8474
40.6k
                         size_to_int(vt.size() / 2), &vi, context)) {
8475
56
          if (err) {
8476
56
            (*err) += sr.format_error(filename,
8477
56
                "failed to parse `p' line (invalid vertex index)");
8478
56
          }
8479
56
          return false;
8480
56
        }
8481
8482
40.6k
        pts.vertex_indices.push_back(vi);
8483
40.6k
        sr.skip_space_and_cr();
8484
40.6k
        p_loop_iter++;
8485
40.6k
      }
8486
8487
183k
      prim_group.pointsGroup.push_back(pts);
8488
183k
      sr.skip_line();
8489
183k
      continue;
8490
183k
    }
8491
8492
    // face
8493
1.15M
    if (sr.peek() == 'f' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8494
458k
      sr.advance(2);
8495
458k
      sr.skip_space();
8496
8497
458k
      face_t face;
8498
8499
458k
      face.smoothing_group_id = current_smoothing_id;
8500
458k
      face.vertex_indices.reserve(3);
8501
8502
458k
      size_t f_loop_max = sr.remaining() + 1;
8503
458k
      size_t f_loop_iter = 0;
8504
599k
      while (!sr.at_line_end() && sr.peek() != '#' &&
8505
141k
             f_loop_iter < f_loop_max) {
8506
141k
        vertex_index_t vi;
8507
141k
        if (!sr_parseTriple(sr, size_to_int(v.size() / 3),
8508
141k
                         size_to_int(vn.size() / 3),
8509
141k
                         size_to_int(vt.size() / 2), &vi, context)) {
8510
278
          if (err) {
8511
278
            (*err) += sr.format_error(filename,
8512
278
                "failed to parse `f' line (invalid vertex index)");
8513
278
          }
8514
278
          return false;
8515
278
        }
8516
8517
141k
        greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx;
8518
141k
        greatest_vn_idx =
8519
141k
            greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx;
8520
141k
        greatest_vt_idx =
8521
141k
            greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx;
8522
8523
141k
        face.vertex_indices.push_back(vi);
8524
141k
        sr.skip_space_and_cr();
8525
141k
        f_loop_iter++;
8526
141k
      }
8527
8528
457k
      prim_group.faceGroup.push_back(face);
8529
457k
      sr.skip_line();
8530
457k
      continue;
8531
458k
    }
8532
8533
    // use mtl
8534
697k
    if (sr.match("usemtl", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8535
83
      sr.advance(6);
8536
83
      std::string namebuf = sr_parseString(sr);
8537
8538
83
      int newMaterialId = -1;
8539
83
      std::map<std::string, int>::const_iterator it =
8540
83
          material_map.find(namebuf);
8541
83
      if (it != material_map.end()) {
8542
0
        newMaterialId = it->second;
8543
83
      } else {
8544
83
        if (warn) {
8545
83
          (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n";
8546
83
        }
8547
83
      }
8548
8549
83
      if (newMaterialId != material) {
8550
0
        exportGroupsToShape(&shape, prim_group, tags, material, name,
8551
0
                            triangulate, v, warn);
8552
0
        prim_group.faceGroup.clear();
8553
0
        material = newMaterialId;
8554
0
      }
8555
8556
83
      sr.skip_line();
8557
83
      continue;
8558
83
    }
8559
8560
    // load mtl
8561
697k
    if (sr.match("mtllib", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
8562
8.25k
      if (readMatFn) {
8563
8.25k
        sr.advance(7);
8564
8565
8.25k
        std::string line_rest = trimTrailingWhitespace(sr.read_line());
8566
8.25k
        std::vector<std::string> filenames;
8567
8.25k
        SplitString(line_rest, ' ', '\\', filenames);
8568
8.25k
        RemoveEmptyTokens(&filenames);
8569
8570
8.25k
        if (filenames.empty()) {
8571
5.48k
          if (warn) {
8572
5.48k
            std::stringstream ss;
8573
5.48k
            ss << "Looks like empty filename for mtllib. Use default "
8574
5.48k
                  "material (line "
8575
5.48k
               << line_num << ".)\n";
8576
8577
5.48k
            (*warn) += ss.str();
8578
5.48k
          }
8579
5.48k
        } else {
8580
2.76k
          bool found = false;
8581
6.20k
          for (size_t s = 0; s < filenames.size(); s++) {
8582
4.95k
            if (material_filenames.count(filenames[s]) > 0) {
8583
3.35k
              found = true;
8584
3.35k
              continue;
8585
3.35k
            }
8586
8587
1.60k
            std::string warn_mtl;
8588
1.60k
            std::string err_mtl;
8589
1.60k
            bool ok = (*readMatFn)(filenames[s].c_str(), materials,
8590
1.60k
                                   &material_map, &warn_mtl, &err_mtl);
8591
1.60k
            if (warn && (!warn_mtl.empty())) {
8592
12
              (*warn) += warn_mtl;
8593
12
            }
8594
8595
1.60k
            if (err && (!err_mtl.empty())) {
8596
90
              (*err) += err_mtl;
8597
90
            }
8598
8599
1.60k
            if (ok) {
8600
1.51k
              found = true;
8601
1.51k
              material_filenames.insert(filenames[s]);
8602
1.51k
              break;
8603
1.51k
            }
8604
1.60k
          }
8605
8606
2.76k
          if (!found) {
8607
77
            if (warn) {
8608
77
              (*warn) +=
8609
77
                  "Failed to load material file(s). Use default "
8610
77
                  "material.\n";
8611
77
            }
8612
77
          }
8613
2.76k
        }
8614
8.25k
      }
8615
8616
8.25k
      sr.skip_line();
8617
8.25k
      continue;
8618
8.25k
    }
8619
8620
    // group name
8621
689k
    if (sr.peek() == 'g' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8622
      // flush previous face group.
8623
3.11k
      bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8624
3.11k
                                     triangulate, v, warn);
8625
3.11k
      (void)ret;
8626
8627
3.11k
      if (shape.mesh.indices.size() > 0) {
8628
758
        shapes->push_back(shape);
8629
758
      }
8630
8631
3.11k
      shape = shape_t();
8632
8633
      // material = -1;
8634
3.11k
      prim_group.clear();
8635
8636
3.11k
      std::vector<std::string> names;
8637
8638
3.11k
      size_t g_loop_max = sr.remaining() + 1;
8639
3.11k
      size_t g_loop_iter = 0;
8640
538k
      while (!sr.at_line_end() && sr.peek() != '#' &&
8641
535k
             g_loop_iter < g_loop_max) {
8642
535k
        std::string str = sr_parseString(sr);
8643
535k
        names.push_back(str);
8644
535k
        sr.skip_space_and_cr();
8645
535k
        g_loop_iter++;
8646
535k
      }
8647
8648
      // names[0] must be 'g'
8649
8650
3.11k
      if (names.size() < 2) {
8651
        // 'g' with empty names
8652
1.84k
        if (warn) {
8653
1.84k
          std::stringstream ss;
8654
1.84k
          ss << "Empty group name. line: " << line_num << "\n";
8655
1.84k
          (*warn) += ss.str();
8656
1.84k
          name = "";
8657
1.84k
        }
8658
1.84k
      } else {
8659
1.27k
        std::stringstream ss;
8660
1.27k
        ss << names[1];
8661
8662
532k
        for (size_t i = 2; i < names.size(); i++) {
8663
530k
          ss << " " << names[i];
8664
530k
        }
8665
8666
1.27k
        name = ss.str();
8667
1.27k
      }
8668
8669
3.11k
      sr.skip_line();
8670
3.11k
      continue;
8671
3.11k
    }
8672
8673
    // object name
8674
686k
    if (sr.peek() == 'o' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8675
      // flush previous face group.
8676
9.00k
      bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8677
9.00k
                                     triangulate, v, warn);
8678
9.00k
      (void)ret;
8679
8680
9.00k
      if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 ||
8681
7.92k
          shape.points.indices.size() > 0) {
8682
6.49k
        shapes->push_back(shape);
8683
6.49k
      }
8684
8685
      // material = -1;
8686
9.00k
      prim_group.clear();
8687
9.00k
      shape = shape_t();
8688
8689
9.00k
      sr.advance(2);
8690
9.00k
      std::string rest = sr.read_line();
8691
9.00k
      name = rest;
8692
8693
9.00k
      sr.skip_line();
8694
9.00k
      continue;
8695
9.00k
    }
8696
8697
677k
    if (sr.peek() == 't' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8698
574k
      const int max_tag_nums = 8192;
8699
574k
      tag_t tag;
8700
8701
574k
      sr.advance(2);
8702
8703
574k
      tag.name = sr_parseString(sr);
8704
8705
574k
      tag_sizes ts = sr_parseTagTriple(sr);
8706
8707
574k
      if (ts.num_ints < 0) {
8708
232
        ts.num_ints = 0;
8709
232
      }
8710
574k
      if (ts.num_ints > max_tag_nums) {
8711
236
        ts.num_ints = max_tag_nums;
8712
236
      }
8713
8714
574k
      if (ts.num_reals < 0) {
8715
195
        ts.num_reals = 0;
8716
195
      }
8717
574k
      if (ts.num_reals > max_tag_nums) {
8718
242
        ts.num_reals = max_tag_nums;
8719
242
      }
8720
8721
574k
      if (ts.num_strings < 0) {
8722
351
        ts.num_strings = 0;
8723
351
      }
8724
574k
      if (ts.num_strings > max_tag_nums) {
8725
91
        ts.num_strings = max_tag_nums;
8726
91
      }
8727
8728
574k
      tag.intValues.resize(static_cast<size_t>(ts.num_ints));
8729
8730
3.79M
      for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
8731
3.22M
        tag.intValues[i] = sr_parseInt(sr);
8732
3.22M
      }
8733
8734
574k
      tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
8735
2.81M
      for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
8736
2.24M
        tag.floatValues[i] = sr_parseReal(sr);
8737
2.24M
      }
8738
8739
574k
      tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
8740
1.40M
      for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
8741
832k
        tag.stringValues[i] = sr_parseString(sr);
8742
832k
      }
8743
8744
574k
      tags.push_back(tag);
8745
8746
574k
      sr.skip_line();
8747
574k
      continue;
8748
574k
    }
8749
8750
102k
    if (sr.peek() == 's' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8751
      // smoothing group id
8752
1.94k
      sr.advance(2);
8753
1.94k
      sr.skip_space();
8754
8755
1.94k
      if (sr.at_line_end()) {
8756
438
        sr.skip_line();
8757
438
        continue;
8758
438
      }
8759
8760
1.50k
      if (sr.peek() == '\r') {
8761
0
        sr.skip_line();
8762
0
        continue;
8763
0
      }
8764
8765
1.50k
      if (sr.remaining() >= 3 && sr.match("off", 3)) {
8766
334
        current_smoothing_id = 0;
8767
1.17k
      } else {
8768
1.17k
        int smGroupId = sr_parseInt(sr);
8769
1.17k
        if (smGroupId < 0) {
8770
233
          current_smoothing_id = 0;
8771
941
        } else {
8772
941
          current_smoothing_id = static_cast<unsigned int>(smGroupId);
8773
941
        }
8774
1.17k
      }
8775
8776
1.50k
      sr.skip_line();
8777
1.50k
      continue;
8778
1.50k
    }
8779
8780
    // Ignore unknown command.
8781
100k
    sr.skip_line();
8782
100k
  }
8783
8784
  // not all vertices have colors, no default colors desired? -> clear colors
8785
7.58k
  if (!found_all_colors && !default_vcols_fallback) {
8786
0
    vc.clear();
8787
0
  }
8788
8789
7.58k
  if (greatest_v_idx >= size_to_int(v.size() / 3)) {
8790
677
    if (warn) {
8791
677
      std::stringstream ss;
8792
677
      ss << "Vertex indices out of bounds (line " << sr.line_num() << ".)\n\n";
8793
677
      (*warn) += ss.str();
8794
677
    }
8795
677
  }
8796
7.58k
  if (greatest_vn_idx >= size_to_int(vn.size() / 3)) {
8797
53
    if (warn) {
8798
53
      std::stringstream ss;
8799
53
      ss << "Vertex normal indices out of bounds (line " << sr.line_num()
8800
53
         << ".)\n\n";
8801
53
      (*warn) += ss.str();
8802
53
    }
8803
53
  }
8804
7.58k
  if (greatest_vt_idx >= size_to_int(vt.size() / 2)) {
8805
62
    if (warn) {
8806
62
      std::stringstream ss;
8807
62
      ss << "Vertex texcoord indices out of bounds (line " << sr.line_num()
8808
62
         << ".)\n\n";
8809
62
      (*warn) += ss.str();
8810
62
    }
8811
62
  }
8812
8813
7.58k
  bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
8814
7.58k
                                 triangulate, v, warn);
8815
7.58k
  if (ret || shape.mesh.indices.size()) {
8816
1.13k
    shapes->push_back(shape);
8817
1.13k
  }
8818
7.58k
  prim_group.clear();
8819
8820
7.58k
  attrib->vertices.swap(v);
8821
7.58k
  attrib->vertex_weights.swap(vertex_weights);
8822
7.58k
  attrib->normals.swap(vn);
8823
7.58k
  attrib->texcoords.swap(vt);
8824
7.58k
  attrib->texcoord_ws.swap(vt_w);
8825
7.58k
  attrib->colors.swap(vc);
8826
7.58k
  attrib->skin_weights.swap(vw);
8827
8828
7.58k
  return true;
8829
8.54k
}
8830
8831
bool 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
0
             bool triangulate, bool default_vcols_fallback) {
8835
0
  attrib->vertices.clear();
8836
0
  attrib->vertex_weights.clear();
8837
0
  attrib->normals.clear();
8838
0
  attrib->texcoords.clear();
8839
0
  attrib->texcoord_ws.clear();
8840
0
  attrib->colors.clear();
8841
0
  attrib->skin_weights.clear();
8842
0
  shapes->clear();
8843
8844
0
  std::string baseDir = mtl_basedir ? mtl_basedir : "";
8845
0
  if (!baseDir.empty()) {
8846
0
#ifndef _WIN32
8847
0
    const char dirsep = '/';
8848
#else
8849
    const char dirsep = '\\';
8850
#endif
8851
0
    if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep;
8852
0
  }
8853
0
  MaterialFileReader matFileReader(baseDir);
8854
8855
#ifdef TINYOBJLOADER_USE_MMAP
8856
  {
8857
    MappedFile mf;
8858
    if (!mf.open(filename)) {
8859
      if (err) {
8860
        std::stringstream ss;
8861
        ss << "Cannot open file [" << filename << "]\n";
8862
        (*err) = ss.str();
8863
      }
8864
      return false;
8865
    }
8866
    if (mf.size > TINYOBJLOADER_STREAM_READER_MAX_BYTES) {
8867
      if (err) {
8868
        std::stringstream ss;
8869
        ss << "input stream too large (" << mf.size
8870
           << " bytes exceeds limit "
8871
           << TINYOBJLOADER_STREAM_READER_MAX_BYTES << " bytes)\n";
8872
        (*err) += ss.str();
8873
      }
8874
      return false;
8875
    }
8876
    StreamReader sr(mf.data, mf.size);
8877
    return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8878
                           &matFileReader, triangulate, default_vcols_fallback,
8879
                           filename);
8880
  }
8881
#else   // !TINYOBJLOADER_USE_MMAP
8882
#ifdef _WIN32
8883
  std::ifstream ifs(LongPathW(UTF8ToWchar(filename)).c_str());
8884
#else
8885
0
  std::ifstream ifs(filename);
8886
0
#endif
8887
0
  if (!ifs) {
8888
0
    if (err) {
8889
0
      std::stringstream ss;
8890
0
      ss << "Cannot open file [" << filename << "]\n";
8891
0
      (*err) = ss.str();
8892
0
    }
8893
0
    return false;
8894
0
  }
8895
0
  {
8896
0
    StreamReader sr(ifs);
8897
0
    return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8898
0
                           &matFileReader, triangulate, default_vcols_fallback,
8899
0
                           filename);
8900
0
  }
8901
0
#endif  // TINYOBJLOADER_USE_MMAP
8902
0
}
8903
8904
bool 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 /*= NULL*/, bool triangulate,
8908
8.54k
             bool default_vcols_fallback) {
8909
8.54k
  attrib->vertices.clear();
8910
8.54k
  attrib->vertex_weights.clear();
8911
8.54k
  attrib->normals.clear();
8912
8.54k
  attrib->texcoords.clear();
8913
8.54k
  attrib->texcoord_ws.clear();
8914
8.54k
  attrib->colors.clear();
8915
8.54k
  attrib->skin_weights.clear();
8916
8.54k
  shapes->clear();
8917
8918
8.54k
  StreamReader sr(*inStream);
8919
8.54k
  return LoadObjInternal(attrib, shapes, materials, warn, err, sr,
8920
8.54k
                         readMatFn, triangulate, default_vcols_fallback);
8921
8.54k
}
8922
8923
8924
static bool LoadObjWithCallbackInternal(StreamReader &sr,
8925
                                        const callback_t &callback,
8926
                                        void *user_data,
8927
                                        MaterialReader *readMatFn,
8928
                                        std::string *warn,
8929
0
                                        std::string *err) {
8930
0
  if (sr.has_errors()) {
8931
0
    if (err) {
8932
0
      (*err) += sr.get_errors();
8933
0
    }
8934
0
    return false;
8935
0
  }
8936
8937
  // material
8938
0
  std::set<std::string> material_filenames;
8939
0
  std::map<std::string, int> material_map;
8940
0
  int material_id = -1;
8941
8942
0
  std::vector<index_t> indices;
8943
0
  std::vector<material_t> materials;
8944
0
  std::vector<std::string> names;
8945
0
  names.reserve(2);
8946
0
  std::vector<const char *> names_out;
8947
8948
  // Handle BOM
8949
0
  if (sr.remaining() >= 3 &&
8950
0
      static_cast<unsigned char>(sr.peek()) == 0xEF &&
8951
0
      static_cast<unsigned char>(sr.peek_at(1)) == 0xBB &&
8952
0
      static_cast<unsigned char>(sr.peek_at(2)) == 0xBF) {
8953
0
    sr.advance(3);
8954
0
  }
8955
8956
0
  while (!sr.eof()) {
8957
0
    sr.skip_space();
8958
0
    if (sr.at_line_end()) { sr.skip_line(); continue; }
8959
0
    if (sr.peek() == '#') { sr.skip_line(); continue; }
8960
8961
    // vertex
8962
0
    if (sr.peek() == 'v' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
8963
0
      sr.advance(2);
8964
0
      real_t x, y, z;
8965
0
      real_t r, g, b;
8966
8967
0
      int num_components = sr_parseVertexWithColor(&x, &y, &z, &r, &g, &b, sr, err, std::string());
8968
0
      if (num_components < 0) {
8969
0
        return false;
8970
0
      }
8971
0
      if (callback.vertex_cb) {
8972
0
        callback.vertex_cb(user_data, x, y, z, r);
8973
0
      }
8974
0
      if (callback.vertex_color_cb) {
8975
0
        bool found_color = (num_components == 6);
8976
0
        callback.vertex_color_cb(user_data, x, y, z, r, g, b, found_color);
8977
0
      }
8978
0
      sr.skip_line();
8979
0
      continue;
8980
0
    }
8981
8982
    // normal
8983
0
    if (sr.peek() == 'v' && sr.peek_at(1) == 'n' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
8984
0
      sr.advance(3);
8985
0
      real_t x, y, z;
8986
0
      sr_parseReal3(&x, &y, &z, sr);
8987
0
      if (callback.normal_cb) {
8988
0
        callback.normal_cb(user_data, x, y, z);
8989
0
      }
8990
0
      sr.skip_line();
8991
0
      continue;
8992
0
    }
8993
8994
    // texcoord
8995
0
    if (sr.peek() == 'v' && sr.peek_at(1) == 't' && (sr.peek_at(2) == ' ' || sr.peek_at(2) == '\t')) {
8996
0
      sr.advance(3);
8997
0
      real_t x, y, z;
8998
0
      sr_parseReal3(&x, &y, &z, sr);
8999
0
      if (callback.texcoord_cb) {
9000
0
        callback.texcoord_cb(user_data, x, y, z);
9001
0
      }
9002
0
      sr.skip_line();
9003
0
      continue;
9004
0
    }
9005
9006
    // face
9007
0
    if (sr.peek() == 'f' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
9008
0
      sr.advance(2);
9009
0
      sr.skip_space();
9010
9011
0
      indices.clear();
9012
0
      size_t cf_loop_max = sr.remaining() + 1;
9013
0
      size_t cf_loop_iter = 0;
9014
0
      while (!sr.at_line_end() && sr.peek() != '#' &&
9015
0
             cf_loop_iter < cf_loop_max) {
9016
0
        vertex_index_t vi = sr_parseRawTriple(sr);
9017
9018
0
        index_t idx;
9019
0
        idx.vertex_index = vi.v_idx;
9020
0
        idx.normal_index = vi.vn_idx;
9021
0
        idx.texcoord_index = vi.vt_idx;
9022
9023
0
        indices.push_back(idx);
9024
0
        sr.skip_space_and_cr();
9025
0
        cf_loop_iter++;
9026
0
      }
9027
9028
0
      if (callback.index_cb && indices.size() > 0) {
9029
0
        callback.index_cb(user_data, &indices.at(0),
9030
0
                          static_cast<int>(indices.size()));
9031
0
      }
9032
9033
0
      sr.skip_line();
9034
0
      continue;
9035
0
    }
9036
9037
    // use mtl
9038
0
    if (sr.match("usemtl", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
9039
0
      sr.advance(6);
9040
0
      std::string namebuf = sr_parseString(sr);
9041
9042
0
      int newMaterialId = -1;
9043
0
      std::map<std::string, int>::const_iterator it =
9044
0
          material_map.find(namebuf);
9045
0
      if (it != material_map.end()) {
9046
0
        newMaterialId = it->second;
9047
0
      } else {
9048
0
        if (warn && (!callback.usemtl_cb)) {
9049
0
          (*warn) += "material [ " + namebuf + " ] not found in .mtl\n";
9050
0
        }
9051
0
      }
9052
9053
0
      if (newMaterialId != material_id) {
9054
0
        material_id = newMaterialId;
9055
0
      }
9056
9057
0
      if (callback.usemtl_cb) {
9058
0
        callback.usemtl_cb(user_data, namebuf.c_str(), material_id);
9059
0
      }
9060
9061
0
      sr.skip_line();
9062
0
      continue;
9063
0
    }
9064
9065
    // load mtl
9066
0
    if (sr.match("mtllib", 6) && (sr.peek_at(6) == ' ' || sr.peek_at(6) == '\t')) {
9067
0
      if (readMatFn) {
9068
0
        sr.advance(7);
9069
9070
0
        std::string line_rest = trimTrailingWhitespace(sr.read_line());
9071
0
        std::vector<std::string> filenames;
9072
0
        SplitString(line_rest, ' ', '\\', filenames);
9073
0
        RemoveEmptyTokens(&filenames);
9074
9075
0
        if (filenames.empty()) {
9076
0
          if (warn) {
9077
0
            (*warn) +=
9078
0
                "Looks like empty filename for mtllib. Use default "
9079
0
                "material. \n";
9080
0
          }
9081
0
        } else {
9082
0
          bool found = false;
9083
0
          for (size_t s = 0; s < filenames.size(); s++) {
9084
0
            if (material_filenames.count(filenames[s]) > 0) {
9085
0
              found = true;
9086
0
              continue;
9087
0
            }
9088
9089
0
            std::string warn_mtl;
9090
0
            std::string err_mtl;
9091
0
            bool ok = (*readMatFn)(filenames[s].c_str(), &materials,
9092
0
                                   &material_map, &warn_mtl, &err_mtl);
9093
9094
0
            if (warn && (!warn_mtl.empty())) {
9095
0
              (*warn) += warn_mtl;
9096
0
            }
9097
9098
0
            if (err && (!err_mtl.empty())) {
9099
0
              (*err) += err_mtl;
9100
0
            }
9101
9102
0
            if (ok) {
9103
0
              found = true;
9104
0
              material_filenames.insert(filenames[s]);
9105
0
              break;
9106
0
            }
9107
0
          }
9108
9109
0
          if (!found) {
9110
0
            if (warn) {
9111
0
              (*warn) +=
9112
0
                  "Failed to load material file(s). Use default "
9113
0
                  "material.\n";
9114
0
            }
9115
0
          } else {
9116
0
            if (callback.mtllib_cb && !materials.empty()) {
9117
0
              callback.mtllib_cb(user_data, &materials.at(0),
9118
0
                                 static_cast<int>(materials.size()));
9119
0
            }
9120
0
          }
9121
0
        }
9122
0
      }
9123
9124
0
      sr.skip_line();
9125
0
      continue;
9126
0
    }
9127
9128
    // group name
9129
0
    if (sr.peek() == 'g' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
9130
0
      names.clear();
9131
9132
0
      size_t cg_loop_max = sr.remaining() + 1;
9133
0
      size_t cg_loop_iter = 0;
9134
0
      while (!sr.at_line_end() && sr.peek() != '#' &&
9135
0
             cg_loop_iter < cg_loop_max) {
9136
0
        std::string str = sr_parseString(sr);
9137
0
        names.push_back(str);
9138
0
        sr.skip_space_and_cr();
9139
0
        cg_loop_iter++;
9140
0
      }
9141
9142
0
      assert(names.size() > 0);
9143
9144
0
      if (callback.group_cb) {
9145
0
        if (names.size() > 1) {
9146
0
          names_out.resize(names.size() - 1);
9147
0
          for (size_t j = 0; j < names_out.size(); j++) {
9148
0
            names_out[j] = names[j + 1].c_str();
9149
0
          }
9150
0
          callback.group_cb(user_data, &names_out.at(0),
9151
0
                            static_cast<int>(names_out.size()));
9152
9153
0
        } else {
9154
0
          callback.group_cb(user_data, NULL, 0);
9155
0
        }
9156
0
      }
9157
9158
0
      sr.skip_line();
9159
0
      continue;
9160
0
    }
9161
9162
    // object name
9163
0
    if (sr.peek() == 'o' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
9164
0
      sr.advance(2);
9165
0
      std::string object_name = sr.read_line();
9166
9167
0
      if (callback.object_cb) {
9168
0
        callback.object_cb(user_data, object_name.c_str());
9169
0
      }
9170
9171
0
      sr.skip_line();
9172
0
      continue;
9173
0
    }
9174
9175
#if 0  // @todo
9176
    if (sr.peek() == 't' && (sr.peek_at(1) == ' ' || sr.peek_at(1) == '\t')) {
9177
      tag_t tag;
9178
9179
      sr.advance(2);
9180
      tag.name = sr_parseString(sr);
9181
9182
      tag_sizes ts = sr_parseTagTriple(sr);
9183
9184
      tag.intValues.resize(static_cast<size_t>(ts.num_ints));
9185
9186
      for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
9187
        tag.intValues[i] = sr_parseInt(sr);
9188
      }
9189
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);
9193
      }
9194
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);
9198
      }
9199
9200
      tags.push_back(tag);
9201
    }
9202
#endif
9203
9204
    // Ignore unknown command.
9205
0
    sr.skip_line();
9206
0
  }
9207
9208
0
  return true;
9209
0
}
9210
9211
bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
9212
                         void *user_data /*= NULL*/,
9213
                         MaterialReader *readMatFn /*= NULL*/,
9214
                         std::string *warn, /* = NULL*/
9215
0
                         std::string *err /*= NULL*/) {
9216
0
  StreamReader sr(inStream);
9217
0
  return LoadObjWithCallbackInternal(sr, callback, user_data, readMatFn,
9218
0
                                     warn, err);
9219
0
}
9220
9221
bool ObjReader::ParseFromFile(const std::string &filename,
9222
0
                              const ObjReaderConfig &config) {
9223
0
  std::string mtl_search_path;
9224
9225
0
  if (config.mtl_search_path.empty()) {
9226
    //
9227
    // split at last '/'(for unixish system) or '\\'(for windows) to get
9228
    // the base directory of .obj file
9229
    //
9230
0
    size_t pos = filename.find_last_of("/\\");
9231
0
    if (pos != std::string::npos) {
9232
0
      mtl_search_path = filename.substr(0, pos);
9233
0
    }
9234
0
  } else {
9235
0
    mtl_search_path = config.mtl_search_path;
9236
0
  }
9237
9238
0
  valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
9239
0
                   filename.c_str(), mtl_search_path.c_str(),
9240
0
                   config.triangulate, config.vertex_color);
9241
9242
0
  return valid_;
9243
0
}
9244
9245
bool ObjReader::ParseFromString(const std::string &obj_text,
9246
                                const std::string &mtl_text,
9247
8.54k
                                const ObjReaderConfig &config) {
9248
8.54k
  std::stringbuf obj_buf(obj_text);
9249
8.54k
  std::stringbuf mtl_buf(mtl_text);
9250
9251
8.54k
  std::istream obj_ifs(&obj_buf);
9252
8.54k
  std::istream mtl_ifs(&mtl_buf);
9253
9254
8.54k
  MaterialStreamReader mtl_ss(mtl_ifs);
9255
9256
8.54k
  valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
9257
8.54k
                   &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color);
9258
9259
8.54k
  return valid_;
9260
8.54k
}
9261
9262
#ifdef __clang__
9263
#pragma clang diagnostic pop
9264
#endif
9265
}  // namespace tinyobj
9266
9267
#endif