GEOS
Logger.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
20 #ifndef GEOS_COMMON_LOGGER_HPP
21 #define GEOS_COMMON_LOGGER_HPP
22 
23 // Source includes
24 #include "LvArray/src/Macros.hpp"
26 
27 // System includes
28 #include <stdexcept>
29 
30 #if defined(GEOS_USE_MPI)
31  #include <mpi.h>
32 #endif
33 
38 #define GEOS_LOG( ... ) LVARRAY_LOG( __VA_ARGS__ )
39 
44 #define GEOS_LOG_VAR( ... ) LVARRAY_LOG_VAR( __VA_ARGS__ )
45 
46 
52 #if defined(GEOS_DEVICE_COMPILE)
53 #define GEOS_LOG_IF( EXP, msg )
54 #else
55 #define GEOS_LOG_IF( EXP, msg ) \
56  do { \
57  if( EXP ) \
58  { \
59  std::cout<< msg << std::endl; \
60  } \
61  } while( false )
62 #endif
63 
64 
70 #define GEOS_LOG_RANK_0_IF( EXP, msg ) \
71  do { \
72  if( ::geos::logger::internal::g_rank == 0 && EXP ) \
73  { \
74  std::ostringstream oss; \
75  oss << msg; \
76  std::cout << oss.str() << std::endl; \
77  } \
78  } while( false )
79 
85 #define GEOS_LOG_RANK_0_IF_NLR( EXP, msg ) \
86  do { \
87  if( ::geos::logger::internal::g_rank == 0 && EXP ) \
88  { \
89  std::ostringstream oss; \
90  oss << msg; \
91  std::cout << oss.str(); \
92  } \
93  } while( false )
94 
99 #define GEOS_LOG_RANK_0( msg ) GEOS_LOG_RANK_0_IF( true, msg )
100 
106 #if defined(GEOS_DEVICE_COMPILE)
107 #define GEOS_LOG_RANK_IF( EXP, msg )
108 #else
109 #define GEOS_LOG_RANK_IF( EXP, msg ) \
110  do { \
111  if( EXP ) \
112  { \
113  std::ostringstream oss; \
114  oss << "Rank " << ::geos::logger::internal::g_rankString << ": " << msg; \
115  *logger::internal::g_rankStream << oss.str() << std::endl; \
116  } \
117  } while( false )
118 #endif
119 
124 #define GEOS_LOG_RANK( msg ) GEOS_LOG_RANK_IF( true, msg )
125 
130 #define GEOS_LOG_RANK_VAR( var ) GEOS_LOG_RANK( #var " = " << var )
131 
137 #if !defined(GEOS_DEVICE_COMPILE) && !defined(GEOS_GLOBAL_LOGGER)
138 #define GEOS_GLOBAL_LOGGER ErrorLogger::global()
139 #endif
140 
150 #if !defined(GEOS_DEVICE_COMPILE)
151 #define GEOS_ERROR_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
152  do \
153  { \
154  if( COND ) \
155  { \
156  std::ostringstream __msgoss; \
157  __msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \
158  std::ostringstream __causemsgsoss; \
159  __causemsgsoss << CAUSE_MESSAGE; \
160  GEOS_GLOBAL_LOGGER.initCurrentExceptionMessage( MsgType::Error, __msgoss.str(), \
161  ::geos::logger::internal::g_rank ) \
162  .setCodeLocation( __FILE__, __LINE__ ) \
163  .setCause( __causemsgsoss.str() ) \
164  .addCallStackInfo( LvArray::system::stackTrace( true ) ) \
165  .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )); \
166  GEOS_GLOBAL_LOGGER.flushCurrentExceptionMessage(); \
167  LvArray::system::callErrorHandler(); \
168  } \
169  }while( false )
170  #elif __CUDA_ARCH__
171 #define GEOS_ERROR_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
172  do \
173  { \
174  if( COND ) \
175  { \
176  constexpr char const * formatString = "***** ERROR\n" \
177  "***** LOCATION" LOCATION "\n" \
178  "***** BLOCK: [%u, %u, %u]\n" \
179  "***** THREAD: [%u, %u, %u]\n" \
180  "***** %s\n" \
181  "***** %s\n\n"; \
182  printf( formatString, blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, threadIdx.z, \
183  STRINGIZE( CAUSE_MESSAGE ), STRINGIZE( GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ) ) ); \
184  asm ( "trap;" ); \
185  } \
186  } while( false )
187 #elif __HIP_DEVICE_COMPILE__
188 /*
189  * ROCm's device-side printf makes otherwise valid kernels fail at launch on
190  * some AMD GPUs (including gfx1100). Keep device checks terminating, but use
191  * a trap instruction without printf.
192  * Host-side diagnostics are unchanged.
193  */
194 #define GEOS_ERROR_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
195  do \
196  { \
197  if( COND ) \
198  { \
199  asm volatile ( "s_trap 2" ); \
200  } \
201  } while( false )
202 #endif
203 
211 #define GEOS_ERROR_IF( COND, ... ) \
212  GEOS_ERROR_IF_CAUSE( COND, "Error cause: " STRINGIZE( COND ), __VA_ARGS__ )
213 
220 #define GEOS_ERROR( ... ) GEOS_ERROR_IF_CAUSE( true, "", __VA_ARGS__ )
221 
231 #if !defined(GEOS_DEVICE_COMPILE)
232 #define GEOS_THROW_IF_CAUSE( COND, CAUSE_MESSAGE, MSG, ... ) \
233  do \
234  { \
235  if( COND ) \
236  { \
237  std::ostringstream __msgoss; \
238  __msgoss << MSG; \
239  std::ostringstream __causemsgsoss; \
240  __causemsgsoss << CAUSE_MESSAGE; \
241  DiagnosticMsg exceptionMsg = GEOS_GLOBAL_LOGGER.initCurrentExceptionMessage( MsgType::Exception, __msgoss.str(), \
242  ::geos::logger::internal::g_rank ) \
243  .setCodeLocation( __FILE__, __LINE__ ) \
244  .setCause( __causemsgsoss.str() ) \
245  .addCallStackInfo( LvArray::system::stackTrace( true ) ) \
246  .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )) \
247  .getDiagnosticMsg(); \
248  auto ex = GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ )(); \
249  ex.prepareWhat( exceptionMsg ); \
250  throw ex; \
251  } \
252  }while( false )
253 #elif __CUDA_ARCH__
254 #define GEOS_THROW_IF_CAUSE( COND, CAUSE_MESSAGE, MSG, ... ) \
255  do \
256  { \
257  if( COND ) \
258  { \
259  static char const formatString[] = "***** ERROR\n" \
260  "***** LOCATION" LOCATION "\n" \
261  "***** BLOCK: [%u, %u, %u]\n" \
262  "***** THREAD: [%u, %u, %u]\n" \
263  "***** %s\n" \
264  "***** %s\n\n"; \
265  printf( formatString, blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, threadIdx.z, \
266  STRINGIZE( CAUSE_MESSAGE ), STRINGIZE( GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ) ) ); \
267  asm ( "trap;" ); \
268  } \
269  } while( false )
270 #elif __HIP_DEVICE_COMPILE__
271 #define GEOS_THROW_IF_CAUSE( COND, CAUSE_MESSAGE, MSG, ... ) \
272  do \
273  { \
274  if( COND ) \
275  { \
276  asm volatile ( "s_trap 2" ); \
277  } \
278  } while( false )
279 #endif
280 
289 #define GEOS_THROW_IF( COND, MSG, ... ) \
290  GEOS_THROW_IF_CAUSE( COND, "Error cause: " STRINGIZE( COND ), MSG, __VA_ARGS__ )
291 
299 #define GEOS_THROW( MSG, ... ) GEOS_THROW_IF_CAUSE( true, "", MSG, __VA_ARGS__ )
300 
309 #if !defined(GEOS_DEVICE_COMPILE)
310 #define GEOS_WARNING_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
311  do \
312  { \
313  if( COND ) \
314  { \
315  std::ostringstream __msgoss; \
316  __msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \
317  std::ostringstream __causemsgsoss; \
318  __causemsgsoss << CAUSE_MESSAGE; \
319  DiagnosticMsg __warningMsg; \
320  GEOS_GLOBAL_LOGGER.flushErrorMsg( DiagnosticMsgBuilder::init( __warningMsg, \
321  MsgType::Warning, __msgoss.str(), \
322  ::geos::logger::internal::g_rank ) \
323  .setCodeLocation( __FILE__, __LINE__ ) \
324  .setCause( __causemsgsoss.str() ) \
325  .addCallStackInfo( LvArray::system::stackTrace( true ) ) \
326  .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )) \
327  .getDiagnosticMsg() ); \
328  } \
329  }while( false )
330 #elif __CUDA_ARCH__
331 #define GEOS_WARNING_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
332  do \
333  { \
334  if( COND ) \
335  { \
336  static char const formatString[] = "***** WARNING\n" \
337  "***** LOCATION" LOCATION "\n" \
338  "***** BLOCK: [%u, %u, %u]\n" \
339  "***** THREAD: [%u, %u, %u]\n" \
340  "***** %s\n" \
341  "***** %s\n\n"; \
342  printf( formatString, blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, threadIdx.z, \
343  STRINGIZE( CAUSE_MESSAGE ), STRINGIZE( GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ) ) ); \
344  asm ( "trap;" ); \
345  } \
346  } while( false )
347 #elif __HIP_DEVICE_COMPILE__
348 #define GEOS_WARNING_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \
349  do \
350  { \
351  if( COND ) \
352  { \
353  asm volatile ( "s_trap 2" ); \
354  } \
355  } while( false )
356 #endif
357 
365 #define GEOS_WARNING_IF( COND, ... ) \
366  GEOS_WARNING_IF_CAUSE( COND, "Warning cause: " STRINGIZE( COND ), __VA_ARGS__ )
367 
374 #define GEOS_WARNING( ... ) GEOS_WARNING_IF_CAUSE( true, "", __VA_ARGS__ )
375 
381 #define GEOS_INFO_IF( EXP, msg ) LVARRAY_INFO_IF( EXP, msg )
382 
387 #define GEOS_INFO( msg ) LVARRAY_INFO( msg )
388 
394 #define GEOS_ERROR_LHS_RHS_DECLS( lhs, rhs ) \
395  GEOS_MAYBE_UNUSED auto const lhsResult = (lhs); \
396  GEOS_MAYBE_UNUSED auto const rhsResult = (rhs)
397 
408 #define GEOS_ERROR_IF_OP_MSG( lhs, OP, NOP, rhs, ... ) \
409  do { \
410  GEOS_ERROR_LHS_RHS_DECLS( lhs, rhs ); \
411  GEOS_ERROR_IF_CAUSE( lhsResult OP rhsResult, \
412  "Expected: " #lhs " " #NOP " " #rhs "\n* " #lhs " = " << lhsResult << "\n* " #rhs " = " << rhsResult << "\n", \
413  __VA_ARGS__ ); \
414  } while(false)
415 
416 
425 #define GEOS_ERROR_IF_EQ_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, ==, !=, rhs, __VA_ARGS__ )
426 
432 #define GEOS_ERROR_IF_EQ( lhs, rhs ) GEOS_ERROR_IF_EQ_MSG( lhs, rhs, "" )
433 
442 #define GEOS_ERROR_IF_NE_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, !=, ==, rhs, __VA_ARGS__ )
443 
449 #define GEOS_ERROR_IF_NE( lhs, rhs ) GEOS_ERROR_IF_NE_MSG( lhs, rhs, "" )
450 
459 #define GEOS_ERROR_IF_GT_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, >, <=, rhs, __VA_ARGS__ )
460 
466 #define GEOS_ERROR_IF_GT( lhs, rhs ) GEOS_ERROR_IF_GT_MSG( lhs, rhs, "" )
467 
476 #define GEOS_ERROR_IF_GE_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, >=, <, rhs, __VA_ARGS__ )
477 
483 #define GEOS_ERROR_IF_GE( lhs, rhs ) GEOS_ERROR_IF_GE_MSG( lhs, rhs, "" )
484 
493 #define GEOS_ERROR_IF_LT_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, <, >=, rhs, __VA_ARGS__ )
494 
500 #define GEOS_ERROR_IF_LT( lhs, rhs ) GEOS_ERROR_IF_LT_MSG( lhs, rhs, "" )
501 
510 #define GEOS_ERROR_IF_LE_MSG( lhs, rhs, ... ) GEOS_ERROR_IF_OP_MSG( lhs, <=, >, rhs, __VA_ARGS__ )
511 
512 
518 #define GEOS_ERROR_IF_LE( lhs, rhs ) GEOS_ERROR_IF_LE_MSG( lhs, rhs, "" )
519 
530 #define GEOS_WARNING_IF_OP_MSG( lhs, OP, NOP, rhs, ... ) \
531  do { \
532  GEOS_ERROR_LHS_RHS_DECLS( lhs, rhs ); \
533  GEOS_WARNING_IF_CAUSE( lhsResult OP rhsResult, \
534  "Expected: " #lhs " " #NOP " " #rhs "\n* " #lhs " = " << lhsResult << "\n* " #rhs " = " << rhsResult << "\n", \
535  __VA_ARGS__ ); \
536  } while(false)
537 
538 
547 #define GEOS_WARNING_IF_EQ_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, ==, !=, rhs, __VA_ARGS__ )
548 
554 #define GEOS_WARNING_IF_EQ( lhs, rhs ) GEOS_WARNING_IF_EQ_MSG( lhs, rhs, "" )
555 
564 #define GEOS_WARNING_IF_NE_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, !=, ==, rhs, __VA_ARGS__ )
565 
571 #define GEOS_WARNING_IF_NE( lhs, rhs ) GEOS_WARNING_IF_NE_MSG( lhs, rhs, "" )
572 
581 #define GEOS_WARNING_IF_GT_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, >, <=, rhs, __VA_ARGS__ )
582 
588 #define GEOS_WARNING_IF_GT( lhs, rhs ) GEOS_WARNING_IF_GT_MSG( lhs, rhs, "" )
589 
598 #define GEOS_WARNING_IF_GE_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, >=, <, rhs, __VA_ARGS__ )
599 
605 #define GEOS_WARNING_IF_GE( lhs, rhs ) GEOS_WARNING_IF_GE_MSG( lhs, rhs, "" )
606 
615 #define GEOS_WARNING_IF_LT_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, <, >=, rhs, __VA_ARGS__ )
616 
622 #define GEOS_WARNING_IF_LT( lhs, rhs ) GEOS_WARNING_IF_LT_MSG( lhs, rhs, "" )
623 
632 #define GEOS_WARNING_IF_LE_MSG( lhs, rhs, ... ) GEOS_WARNING_IF_OP_MSG( lhs, <=, >, rhs, __VA_ARGS__ )
633 
639 #define GEOS_WARNING_IF_LE( lhs, rhs ) GEOS_WARNING_IF_LE_MSG( lhs, rhs, "" )
640 
652 #define GEOS_THROW_IF_OP_MSG( lhs, OP, NOP, rhs, MSG, ... ) \
653  do { \
654  GEOS_ERROR_LHS_RHS_DECLS( lhs, rhs ); \
655  GEOS_THROW_IF_CAUSE( lhsResult OP rhsResult, \
656  "Expected: " #lhs " " #NOP " " #rhs "\n* " #lhs " = " << lhsResult << "\n* " #rhs " = " << rhsResult << "\n", \
657  MSG, __VA_ARGS__ ); \
658  } while(false)
659 
660 
661 
671 #define GEOS_THROW_IF_EQ_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, ==, !=, rhs, MSG, __VA_ARGS__ )
672 
681 #define GEOS_THROW_IF_EQ( lhs, rhs, ... ) GEOS_THROW_IF_EQ_MSG( lhs, rhs, "", __VA_ARGS__ )
682 
692 #define GEOS_THROW_IF_NE_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, !=, ==, rhs, MSG, __VA_ARGS__ )
693 
702 #define GEOS_THROW_IF_NE( lhs, rhs, ... ) GEOS_THROW_IF_NE_MSG( lhs, rhs, "", __VA_ARGS__ )
703 
713 #define GEOS_THROW_IF_GT_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, >, <=, rhs, MSG, __VA_ARGS__ )
714 
723 #define GEOS_THROW_IF_GT( lhs, rhs, ... ) GEOS_THROW_IF_GT_MSG( lhs, rhs, "", __VA_ARGS__ )
724 
734 #define GEOS_THROW_IF_GE_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, >=, <, rhs, MSG, __VA_ARGS__ )
735 
744 #define GEOS_THROW_IF_GE( lhs, rhs, ... ) GEOS_THROW_IF_GE_MSG( lhs, rhs, "", __VA_ARGS__ )
745 
755 #define GEOS_THROW_IF_LT_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, <, >=, rhs, MSG, __VA_ARGS__ )
756 
765 #define GEOS_THROW_IF_LT( lhs, rhs, ... ) GEOS_THROW_IF_LT_MSG( lhs, rhs, "", __VA_ARGS__ )
766 
776 #define GEOS_THROW_IF_LE_MSG( lhs, rhs, MSG, ... ) GEOS_THROW_IF_OP_MSG( lhs, <=, >, rhs, MSG, __VA_ARGS__ )
777 
786 #define GEOS_THROW_IF_LE( lhs, rhs, ... ) GEOS_THROW_IF_LE_MSG( lhs, rhs, "", __VA_ARGS__ )
787 
788 #if !defined(NDEBUG) || defined(GEOS_ASSERT_ENABLED)
789 
793 #define GEOS_ASSERT_ENABLED
794 
807 #define GEOS_ASSERT_MSG( COND, ... ) \
808  GEOS_ERROR_IF_CAUSE( !( COND ), "Expected: " STRINGIZE( COND ), __VA_ARGS__ )
809 
819 #define GEOS_ASSERT_OP_MSG( lhs, OP, rhs, ... ) \
820  { \
821  GEOS_ERROR_LHS_RHS_DECLS( lhs, rhs ); \
822  GEOS_ERROR_IF_CAUSE( !( lhsResult OP rhsResult ), \
823  "Expected: " #lhs " " #OP " " #rhs "\n* " #lhs " = " << lhsResult << "\n* " #rhs " = " << rhsResult << "\n", \
824  __VA_ARGS__ ); \
825  }
826 
827 #else
828 
829 #define GEOS_ASSERT_MSG( ... ) ((void) 0)
830 #define GEOS_ASSERT_OP_MSG( ... ) ((void) 0)
831 
832 #endif
833 
838 #define GEOS_ASSERT( COND ) GEOS_ASSERT_MSG( COND, "" )
839 
848 #define GEOS_ASSERT_EQ_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, ==, rhs, __VA_ARGS__ )
849 
855 #define GEOS_ASSERT_EQ( lhs, rhs ) GEOS_ASSERT_EQ_MSG( lhs, rhs, "" )
856 
865 #define GEOS_ASSERT_NE_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, !=, rhs, __VA_ARGS__ )
866 
872 #define GEOS_ASSERT_NE( lhs, rhs ) GEOS_ASSERT_NE_MSG( lhs, rhs, "" )
873 
882 #define GEOS_ASSERT_GT_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, >, rhs, __VA_ARGS__ )
883 
889 #define GEOS_ASSERT_GT( lhs, rhs ) GEOS_ASSERT_GT_MSG( lhs, rhs, "" )
890 
899 #define GEOS_ASSERT_GE_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, >=, rhs, __VA_ARGS__ )
900 
906 #define GEOS_ASSERT_GE( lhs, rhs ) GEOS_ASSERT_GE_MSG( lhs, rhs, "" )
907 
916 #define GEOS_ASSERT_LT_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, <, rhs, __VA_ARGS__ )
917 
923 #define GEOS_ASSERT_LT( lhs, rhs ) GEOS_ASSERT_LT_MSG( lhs, rhs, "" )
924 
933 #define GEOS_ASSERT_LE_MSG( lhs, rhs, ... ) GEOS_ASSERT_OP_MSG( lhs, <=, rhs, __VA_ARGS__ )
934 
940 #define GEOS_ASSERT_LE( lhs, rhs ) GEOS_ASSERT_LE_MSG( lhs, rhs, "" )
941 
942 namespace geos
943 {
944 
945 namespace logger
946 {
947 
948 namespace internal
949 {
950 
951 extern int g_rank;
952 
953 extern std::string g_rankString;
954 
955 extern std::ostream * g_rankStream;
956 
957 } // namespace internal
958 
959 #if defined(GEOS_USE_MPI)
965 void InitializeLogger( MPI_Comm comm, const std::string & rank_output_dir="" );
966 #endif
967 
972 void InitializeLogger( const std::string & rank_output_dir="" );
973 
978 
979 } // namespace logger
980 
981 } // namespace geos
982 
983 #endif /* GEOS_COMMON_LOGGER_HPP */
void FinalizeLogger()
Finalize the logger and close the rank streams.
void InitializeLogger(const std::string &rank_output_dir="")
Initialize the logger in a serial build.
std::string string
String type.
Definition: DataTypes.hpp:90