Files
2025-12-05 08:54:02 +01:00

451 lines
18 KiB
C++

/*
# <<BEGIN-copyright>>
# Copyright 2019, Lawrence Livermore National Security, LLC.
# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
# SPDX-License-Identifier: MIT
# <<END-copyright>>
*/
#ifndef LUPI_hpp_included
#define LUPI_hpp_included 1
#include <sys/stat.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <stdexcept>
#include <iostream>
#ifndef _WIN32
#include <time.h>
#include <sys/time.h>
#endif
#include <LUPI_defines.hpp>
#include <statusMessageReporting.h>
#define LUPI_XML_verionEncoding "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
#ifndef LUPI_PATH_MAX
#define LUPI_PATH_MAX ( 4 * 4096 )
#endif
#if defined (GIDIP_HAVE_COMPILER_FLOATING_POINT_EXCEPTIONS)
void LUPI_FPE_enable( char const *a_file, int a_line );
void LUPI_FPE_disable_and_clear( char const *a_file, int a_line );
void LUPI_FPE_test( char const *a_file, int a_line );
#endif
namespace LUPI {
#ifdef _WIN32
#define LUPI_FILE_SEPARATOR "\\"
#else
#define LUPI_FILE_SEPARATOR "/"
#endif
#define GNDS_formatVersion_1_10Chars "1.10"
#define GNDS_formatVersion_2_0Chars "2.0"
#define GNDS_formatVersion_2_0_LLNL_4Chars "2.0.LLNL_4"
#define GNDS_formatVersion_2_1Chars "2.1"
void deprecatedFunction( std::string const &a_functionName, std::string const &a_replacementName, std::string const &a_asOf );
/*
============================================================
====================== FormatVersion =======================
============================================================
*/
class FormatVersion {
private:
std::string m_format; /**< The GNDS format version. */
int m_major; /**< The GNDS format major value as an integer. */
int m_minor; /**< The GNDS format minor value as an integer. */
std::string m_patch; /**< The GNDS format patch string. This will be an empty string except for unofficial formats. */
public:
FormatVersion( );
FormatVersion( std::string const &a_formatVersion );
FormatVersion( FormatVersion const &a_formatVersion );
FormatVersion &operator=( FormatVersion const &a_rhs );
std::string const &format( ) const { return( m_format ); }
int major( ) const { return( m_major ); }
int minor( ) const { return( m_minor ); }
std::string const &patch( ) const { return( m_patch ); }
bool setFormat( std::string const &a_formatVersion );
bool supported( ) const ;
};
/*
============================================================
========================= Exception ========================
============================================================
*/
class Exception : public std::runtime_error {
public :
explicit Exception( std::string const &a_message );
};
/*
============================================================
================== StatusMessageReporting ==================
============================================================
*/
class StatusMessageReporting {
public:
enum class Status { ok, info, warning, error };
private:
statusMessageReporting m_smr;
public:
StatusMessageReporting( );
~StatusMessageReporting( );
statusMessageReporting *smr( ) { return( &m_smr ); }
bool isOk( ) { return( smr_isOk( &m_smr ) ); }
bool isInfo( ) { return( smr_isInfo( &m_smr ) ); }
bool isWarning( ) { return( smr_isWarning( &m_smr ) ); }
bool isError( ) { return( smr_isError( &m_smr ) ); }
void clear( ) { smr_release( &m_smr ); }
std::string constructMessage( std::string a_prefix, int a_reports = 1, bool a_clear = false );
std::string constructFullMessage( std::string const &a_prefix, int a_reports = 1, bool a_clear = false );
};
/*
============================================================
====================== ArgumentParser ======================
============================================================
*/
enum class ArgumentType { True, False, Count, Store, Append, Positional };
class ArgumentBase;
class ArgumentParser {
private:
std::string m_codeName; /**< The name of the code that is using **ArgumentParser**. */
std::string m_descriptor; /**< The descriptor that is printed when help (i.e., '-h') is entered. */
std::vector<ArgumentBase *> m_arguments; /**< The list of arguments (positional and optional) supported. */
void add2( ArgumentBase *a_argumentBase );
public:
ArgumentParser( std::string const &a_codeName, std::string const &a_descriptor = "" );
~ArgumentParser( );
std::string const &codeName( ) const { return( m_codeName ); }
std::string const &descriptor( ) const { return( m_descriptor ); }
template<typename T> T *add( std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded = 1, int a_maximumNeeded = 1 );
ArgumentBase *add( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor,
int a_minimumNeeded = -2, int a_maximumNeeded = -2 );
void addAlias( std::string const &a_name, std::string const &a_alias );
void addAlias( ArgumentBase const * const a_argumentBase, std::string const &a_alias );
bool hasName( std::string const &a_name ) const ;
bool isOptionalArgument( std::string const &a_name ) const ;
void parse( int a_argc, char **a_argv, bool a_printArguments = true );
template<typename T> T *get( std::size_t a_name );
void help( ) const ;
void usage( ) const ;
virtual void printStatus( std::string a_indent ) const ;
};
/* *********************************************************************************************************//**
* Creates a new argument, adds the argument to *this* and returns a pointer the the newly created argument.
*
* @param a_name [in] The name of the argument.
* @param a_descriptor [in] The argument's description, displayed when the help option is enetered.
* @param a_minimumNeeded [in] The minimum number of required time *this* argument must be entered.
* @param a_maximumNeeded [in] The maximum number of required time *this* argument must be entered.
*
* @return A pointer to the created argument.
***********************************************************************************************************/
template<typename T> T *ArgumentParser::add( std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded ) {
T *argument = new T( a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded );
add2( argument );
return( argument );
}
/*
============================================================
======================= ArgumentBase =======================
============================================================
*/
class ArgumentBase {
private:
ArgumentType m_argumentType; /**< The enum for arguent type of *this*. */
std::vector<std::string> m_names; /**< The allowed names for *this*. */
std::string m_descriptor; /**< The desciption printed help. */
int m_minimumNeeded; /**< Minimum number of times *this* argument is required on the command line. */
int m_maximumNeeded; /**< Maximum number of times *this* argument is required on the command line. */
std::size_t m_counts; /**< The number of time this argument was entered on the command line. */
std::vector<std::string> m_values; /**< list of values entered for this argument. Only used for types Store, Append and Positional. */
void addAlias( std::string const &a_name ); /**< Adds the alias *a_name* to *this*. */
virtual std::string printStatus2( ) const ; /**< For internal use. Called by method **printStatus**. */
virtual void printStatus3( std::string const &a_indent ) const ;
friend void ArgumentParser::addAlias( std::string const &a_name, std::string const &a_alias );
public:
ArgumentBase( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded );
virtual ~ArgumentBase( ) = 0 ;
ArgumentType argumentType( ) const { return( m_argumentType ); }
std::string const &name( ) const { return( m_names[0] ); }
std::vector<std::string> const &names( ) { return( m_names ); }
bool hasName( std::string const &a_name ) const ;
std::string const &descriptor( ) const { return( m_descriptor ); }
int minimumNeeded( ) const { return( m_minimumNeeded ); }
int maximumNeeded( ) const { return( m_maximumNeeded ); }
std::size_t counts( ) const { return( m_counts ); }
virtual std::string const &value( std::size_t a_index = 0 ) const ;
std::vector<std::string> const &values( ) const { return( m_values ); }
virtual bool isOptionalArgument( ) const { return( true ); }
virtual bool requiresAValue( ) const { return( false ); }
virtual int parse( ArgumentParser const &a_argumentParser, int a_index, int a_argc, char **a_argv );
std::string usage( bool a_requiredOption ) const ;
void printStatus( std::string a_indent ) const ;
};
/*
============================================================
======================= OptionBoolean ======================
============================================================
*/
class OptionBoolean : public ArgumentBase {
private:
bool m_default;
public:
OptionBoolean( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, bool a_default );
virtual ~OptionBoolean( ) = 0 ;
bool _default( ) const { return( m_default ); }
std::string printStatus2( ) const ;
};
/*
============================================================
======================== OptionTrue ========================
============================================================
*/
class OptionTrue : public OptionBoolean {
public:
OptionTrue( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 0, int a_maximumNeeded = -1 );
~OptionTrue( ) { }
};
/*
============================================================
======================= OptionFalse ========================
============================================================
*/
class OptionFalse : public OptionBoolean {
public:
OptionFalse( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 0, int a_maximumNeeded = -1 );
~OptionFalse( ) { }
};
/*
============================================================
====================== OptionCounter =======================
============================================================
*/
class OptionCounter : public ArgumentBase {
public:
OptionCounter( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 0, int a_maximumNeeded = -1 );
~OptionCounter( ) { }
std::string printStatus2( ) const ;
};
/*
============================================================
======================= OptionStore ========================
============================================================
*/
class OptionStore : public ArgumentBase {
public:
OptionStore( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 0, int a_maximumNeeded = -1 );
~OptionStore( ) { }
std::string const &value( std::size_t a_index = 0 ) const ;
bool requiresAValue( ) const { return( true ); }
void printStatus3( std::string const &a_indent ) const ;
};
/*
============================================================
======================= OptionAppend =======================
============================================================
*/
class OptionAppend : public ArgumentBase {
public:
OptionAppend( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 0, int a_maximumNeeded = -1 );
~OptionAppend( ) { }
bool requiresAValue( ) const { return( true ); }
void printStatus3( std::string const &a_indent ) const ;
};
/*
============================================================
======================== Positional ========================
============================================================
*/
class Positional : public ArgumentBase {
public:
Positional( std::string const &a_name, std::string const &a_descriptor = "", int a_minimumNeeded = 1, int a_maximumNeeded = 1 );
~Positional( ) { }
bool isOptionalArgument( ) const { return( false ); }
bool requiresAValue( ) const { return( true ); }
void printStatus3( std::string const &a_indent ) const ;
};
/*
============================================================
======================== DeltaTime =========================
============================================================
*/
#ifndef _WIN32
#define LUPI_DeltaTime_toStringFormatIncremental "incremental: CPU %8.3fs, wall %8.3fs"
#define LUPI_DeltaTime_toStringFormatTotal "total: CPU %8.3fs, wall %8.3fs"
class DeltaTime {
private:
double m_CPU_time;
double m_wallTime;
double m_CPU_timeIncremental;
double m_wallTimeIncremental;
public:
DeltaTime( );
DeltaTime( double a_CPU_time, double a_wallTime, double a_CPU_timeIncremental, double a_wallTimeIncremental );
DeltaTime( DeltaTime const &deltaTime );
~DeltaTime( ) { }
double CPU_time( ) const { return( m_CPU_time ); }
double wallTime( ) const { return( m_wallTime ); }
double CPU_timeIncremental( ) const { return( m_CPU_timeIncremental ); }
double wallTimeIncremental( ) const { return( m_wallTimeIncremental ); }
std::string toString( std::string a_formatIncremental = LUPI_DeltaTime_toStringFormatIncremental,
std::string a_format = LUPI_DeltaTime_toStringFormatTotal, std::string a_sep = "; " );
};
/*
============================================================
========================== Timer ===========================
============================================================
*/
class Timer {
private:
clock_t m_CPU_time;
struct timeval m_wallTime;
clock_t m_CPU_timeIncremental;
struct timeval m_wallTimeIncremental;
public:
Timer( );
~Timer( ) { }
DeltaTime deltaTime( );
DeltaTime deltaTimeAndReset( );
void reset( );
};
#endif // End of not _WIN32 defined.
namespace FileInfo { // Should be using std::filesystem stuff but this requires C++ 17.
std::string realPath( std::string const &a_path );
std::string _basename( std::string const &a_path );
std::string basenameWithoutExtension( std::string const &a_path );
std::string _dirname( std::string const &a_path );
bool exists( std::string const &a_path );
bool isDirectory( std::string const &a_path );
bool createDirectories( std::string const &a_path );
/*
============================================================
========================= FileStat =========================
============================================================
*/
class FileStat {
private:
std::string m_path; /**< The path that is stat-ed. */
struct stat m_stat; /**< The stat for the path. */
public:
FileStat( std::string const &a_path );
std::string const &path( ) const { return( m_path ); } /**< Returns a reference to the **m_path** member. */
struct stat const &statRef( ) const { return( m_stat ); } /**< Returns a reference to the **m_stat** member. */
bool exists( );
bool isDirectory( ) const { return( ( m_stat.st_mode & S_IFMT ) == S_IFDIR ); } /**< Returns *true* if the path is a directory and *false* otherwise. */
bool isRegularFile( ) const { return( ( m_stat.st_mode & S_IFMT ) == S_IFREG ); } /**< Returns *true* if the path is a regular file and *false* otherwise. */
};
} // End of namespace FileInfo.
// Miscellaneous functions
namespace Misc {
std::string stripString( std::string const &a_string, bool a_left = true, bool a_right = true );
std::vector<std::string> splitString( std::string const &a_string, char a_delimiter, bool a_strip = false );
std::vector<std::string> splitString( std::string const &a_string, std::string const &a_delimiter, bool a_strip = false );
std::string joinStrings( std::string const &a_sep, std::vector<std::string> a_strings );
std::string replaceString( std::string const &a_string, std::string const &a_old, std::string const &a_new, bool a_all );
std::vector<std::string> splitXLinkString( std::string const &a_string );
bool stringToInt( std::string const &a_string, int &a_value );
bool stringToSize_t( std::string const &a_string, std::size_t &a_value );
std::string argumentsToString( char const *a_format, ... );
std::string doubleToString3( char const *a_format, double a_value, bool a_reduceBits = false );
std::string doubleToShortestString( double a_value, int a_significantDigits = 15, int a_favorEFormBy = 0 );
void printCommand( std::string const &a_indent, int a_argc, char **a_argv );
} // End of namespace Misc.
} // End of namespace LUPI.
#endif // LUPI_hpp_included