diff --git a/.gitignore b/.gitignore index 1c3574cf..34778a01 100644 --- a/.gitignore +++ b/.gitignore @@ -81,8 +81,8 @@ src/marc # Test Files test-driver -tests/*.log -tests/*.trs +*.log +*.trs tests/DefaultConfiguration_Test tests/Math_Test tests/Vector_Test @@ -94,12 +94,14 @@ tests/LatitudeImage_Test tests/LongitudeImage_Test tests/ViewingGeometry_Test tests/Mercator_Test +tests/Orthographic_Test tests/PolarStereographic_Test +tests/optional_test tests/root_find_test tests/utility_test tests/validate_test tests/test-suite.log -tests/test_map*.fits +tests/test_*map*.fits # Core Dump Files core* diff --git a/.travis.yml b/.travis.yml index cdfbd9b0..83edd99c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,11 +46,6 @@ matrix: - MATRIX_EVAL="CC=clang && CXX=clang++" before_script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - wget https://github.com/gabime/spdlog/archive/v0.17.0.tar.gz -O /tmp/spdlog.tar.gz; - tar xf /tmp/spdlog.tar.gz spdlog-0.17.0/include/; - export CPPFLAGS="$CPPFLAGS -I$PWD/spdlog-0.17.0/include"; - fi - ./bootstrap script: @@ -68,7 +63,7 @@ before_install: fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew install cfitsio bison flex texinfo autoconf-archive spdlog; + brew install cfitsio bison flex texinfo autoconf-archive fmt; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then for p in bison gettext flex texinfo; do @@ -78,5 +73,5 @@ before_install: after_success: - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CXX" == "g++-5" ]]; then - cpp-coveralls --exclude src/parse.hh --exclude src/parse.cc --exclude src/lexer.cc --exclude spdlog-0.17.0 --exclude tests --gcov-options '\-lp'; + cpp-coveralls --exclude src/parse.hh --exclude src/parse.cc --exclude src/lexer.cc --exclude opt --exclude tests --gcov-options '\-lp'; fi diff --git a/Doxyfile b/Doxyfile index 15ff3fe4..49956b04 100644 --- a/Doxyfile +++ b/Doxyfile @@ -444,7 +444,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -781,7 +781,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = lib/MaRC \ +INPUT = lib/marc \ src \ tests \ marc.dox @@ -855,7 +855,11 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = src/parse.{hh,cc} src/lexer.cc +EXCLUDE = lib/marc/config.h \ + src/lexer.cc \ + src/lexer.hh \ + src/parse.cc \ + src/parse.hh # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -2041,7 +2045,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2049,7 +2053,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2081,7 +2085,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = DXGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2090,7 +2094,7 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = MARC_DEBUG_ARGS # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have diff --git a/Makefile.am b/Makefile.am index dc5cb411..e439849c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,9 +38,9 @@ EXTRA_DIST = \ Doxyfile \ marc.dox \ CODE_OF_CONDUCT.md \ - README.md + README.md \ + opt include $(top_srcdir)/aminclude_static.am clean-local: code-coverage-clean -dist-clean-local: code-coverage-dist-clean diff --git a/NEWS b/NEWS index 0535081f..5428a994 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,31 @@ +- Fixed a regression in quadratic roots calculations that caused some + areas of an Orthographic projection to incorrectly have data of + value zero, as well as other coordinate calculations. + +- Blank areas of integer typed maps now contain the user-supplied + DATA_BLANK value, if specified in the MaRC input file. This allows + FITS image readers to easily identify areas of integer typed maps + that lack data. + +- Corrected a problem where MaRC's Simple Cylindrical projection could + not handle the case where lower and upper longitudes in the map were + the same, signifying a 360 degree range, resulting in only single + longitude being mapped across all map pixels. MaRC now assumes the + full 360 degree longitude range is being mapped if both the lower + and upper longitude are the same, and issues a diagnostic message + accordingly. + +- The MU plane no longer needs to have the sub-solar point specified. + It was never needed for emission angle calculations. + +- The MU0 plane no longer needs to have the sub-observer point and + range specified. They were never needed for incidence angle + computations. + +- Improved MaRC input file parser error reporting. The filename, line + number and column containing the syntax error are now reported to + the user. + - Corrected handling of position angles explicity marked as clockwise, i.e. "CW", in MaRC input files. They were erroneously treated as counter-clockwise position angles. @@ -9,10 +37,9 @@ - Added command line option support. Try "marc --help". -- Improved logging by leveraging the spdlog library as the underling +- Improved logging by leveraging the fmt library as the underlying logging framework. This allows for faster logging, and log level - differentiated output (e.g. text color on terminals that support - ANSI colors), as well. + differentiated output. - Corrected progress output for the Orthographic map projection so that completion percentage is printed up to 100%. @@ -179,7 +206,7 @@ - Updated GFDL license terms from 1.2 to 1.3. - Minor optimizations. - Slight reduction in static footprint. -- Fixed a bug MaRC::Vector iteration problem that prevented properly +- Fixed a MaRC::Vector iteration problem that prevented properly mapping images where the latitude and longitude at the optical axis ({LAT,LON}_AT_CENTER) instead of the of body center ({SAMPLE,LINE}_CENTER were given. Support for the LAT_AT_CENTER and diff --git a/README.md b/README.md index bf308965..ee13ef72 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/ossama-othman/MaRC.svg?branch=master)](https://travis-ci.org/ossama-othman/MaRC) +[![Build Status](https://travis-ci.com/ossama-othman/MaRC.svg?branch=master)](https://travis-ci.com/ossama-othman/MaRC) [![Coverity Status](https://scan.coverity.com/projects/13233/badge.svg)](https://scan.coverity.com/projects/ossama-othman-marc) [![Coverage Status](https://coveralls.io/repos/github/ossama-othman/MaRC/badge.svg?branch=master&service=github)](https://coveralls.io/github/ossama-othman/MaRC?branch=master&service=github) @@ -17,16 +17,16 @@ Transport System) format. ## Getting Started -MaRC may either be built from a source tarball or from a clone of its -source repository on GitHub. If you're an end-user that just wants to -run MaRC, building from the self-contained source tarball will get you -up and running sooner. +MaRC may either be built from a source `tar` archive or from a clone +of its source repository on GitHub. If you're an end-user that just +wants to run MaRC, building from the self-contained source `tar` +archive will get you up and running sooner. -### Building From the Source Tarball +### Building From the Source `tar` Archive The quickest way to get started with MaRC is to download the -self-contained source tarball (e.g. `marc-0.9.11.tar.gz`) from the -[releases page](https://github.com/ossama-othman/MaRC/releases). +self-contained source `tar` archive (e.g. `marc-0.9.11.tar.gz`) from +the [releases page](https://github.com/ossama-othman/MaRC/releases). Other than required third party programs and libraries it contains everything needed to build and install MaRC. Once the prerequisites are installed, simply build MaRC as follows: @@ -43,9 +43,9 @@ will be in the "doc" subdirectory if your system has the necessary text utilities to build them. Additional build details and instructions may be found in the -`INSTALL` file shipped with the self-contained source tarball, as well -as by passing the `--help` command line option to the `configure` -script. +`INSTALL` file shipped with the self-contained source `tar` archive, +as well as by passing the `--help` command line option to the +`configure` script. ### Building From Git If you plan on contributing to MaRC or want the latest unreleased @@ -77,9 +77,6 @@ following build dependencies: Additional details are available on the [CFITSIO homepage](https://heasarc.gsfc.nasa.gov/fitsio/fitsio.html). -* [spdlog](https://github.com/gabime/spdlog) logging library - * Prepackaged binaries are available for many platforms. - * [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) #### Maintenance and Git Based Build Dependencies @@ -125,7 +122,7 @@ File | Location ---- | -------- `marc` | `/usr/local/bin` `libmarc` | `/usr/local/lib` -MaRC headers | `/usr/local/include/MaRC` +MaRC headers | `/usr/local/include/marc` documentation | `/usr/local/share/marc` man pages | `/usr/local/share/man/` diff --git a/configure.ac b/configure.ac index b8167400..102f66a5 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ dnl An autoconf script to automatically configure MaRC. AC_PREREQ([2.69]) -AC_INIT([MaRC], [0.9.10], [othman@users.sourceforge.net], [marc]) +AC_INIT([MaRC], [0.10a], [othman@users.sourceforge.net], [marc]) dnl Additional configure script arguments AX_IS_RELEASE([git-directory]) @@ -41,16 +41,16 @@ dnl [with_spdlog=check]) dnl Check what platform we are running on. dnl AC_CANONICAL_TARGET -AM_INIT_AUTOMAKE([1.14.1 check-news silent-rules std-options -Wall -Werror -Wno-portability]) +AM_INIT_AUTOMAKE([1.14.1 check-news silent-rules std-options readme-alpha -Wall -Werror -Wno-portability]) AM_SILENT_RULES([yes]) LT_INIT([disable-static]) AC_CONFIG_MACRO_DIRS([m4]) -AC_CONFIG_SRCDIR([lib/MaRC/PhotoImage.h]) +AC_CONFIG_SRCDIR([lib/marc/PhotoImage.h]) dnl Generate a header file with all settings. -AC_CONFIG_HEADERS([lib/MaRC/config.h]) +AC_CONFIG_HEADERS([lib/marc/config.h]) dnl Checks for programs. AC_PROG_CXX @@ -59,12 +59,12 @@ AC_PROG_LN_S AC_PROG_YACC AM_PROG_LEX -AX_CODE_COVERAGE +MARC_CODE_COVERAGE -# Check for pkg-config +dnl Check for pkg-config PKG_PROG_PKG_CONFIG -# Check for Doxygen +dnl Check for Doxygen DX_DOXYGEN_FEATURE(ON) DX_DOT_FEATURE(ON) DX_HTML_FEATURE(ON) @@ -86,7 +86,7 @@ dnl dnl config.h template dnl -dnl Text to be placed at the top of the `MaRC/config.h' header. +dnl Text to be placed at the top of the `marc/config.h' header. AH_TOP([ /** * @file config.h @@ -101,7 +101,7 @@ AH_TOP([ ]) -dnl Text to be placed at the bottom of the `MaRC/config.h' header. +dnl Text to be placed at the bottom of the `marc/config.h' header. AH_BOTTOM([ #endif /* MARC_CONFIG_H */ @@ -111,8 +111,6 @@ AH_BOTTOM([ ]) -AH_TEMPLATE([MARC_HAS_3_PARAM_STD_HYPOT],[C++ compiler supports C++17 three-parameter std::hypot().]) - dnl Checks for libraries. dnl We're of course going to need the C math library. @@ -142,56 +140,55 @@ AC_SUBST([CFITSIO_LIBS]) AC_SUBST([CFITSIO_CFLAGS]) dnl spdlog requires POSIX threads support. -AX_CXX_PTHREAD -LIBS="$PTHREAD_LIBS $LIBS" -CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" -CXX="$PTHREAD_CXX" - -AC_CACHE_CHECK([for spdlog library], - [marc_cv_lib_spdlog], +dnl AX_CXX_PTHREAD +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" +dnl CXX="$PTHREAD_CXX" + +dnl Workaround AX_CXX_PTHREAD's inability to detect the need for +dnl Clang's -Qunused-arguments command line option in some cases, such +dnl as when building a shared library through Libtool. +dnl AS_IF([test "x$ax_pthread_clang" = "xyes"], +dnl [MARC_UNUSED_ARGUMENT_LDFLAGS="-Xcompiler -Qunused-arguments" +dnl AC_SUBST([MARC_UNUSED_ARGUMENT_LDFLAGS])]) + +AC_CACHE_CHECK([for fmt library], + [marc_cv_lib_fmt], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include +#include ]], [[ -auto logger = spdlog::stdout_color_mt("marc"); - -logger->info("foo"); +void vlog_info(char const * format, fmt::format_args args) +{ + fmt::print("INFO: "); + fmt::vprint(format, args); +} + +template +void log_info(char const * format, const Args & ... args) +{ + vlog_info(format, fmt::make_format_args(args...)); +} + +log_info("{}", "foo"); ]]) ], [ - marc_cv_lib_spdlog=yes + marc_cv_lib_fmt=yes ], [ - marc_cv_lib_spdlog=no + marc_cv_lib_fmt=no ]) ]) dnl ]) -AS_IF([test "x$marc_cv_lib_spdlog" = "xyes"], - [AC_DEFINE([HAVE_SPDLOG], [1], [Define if you have spdlog.])], - [AC_MSG_FAILURE([spdlog library is required])]) - -dnl Check for C++17 three-parameter std::hypot() function. -AC_CACHE_CHECK([if $CXX supports C++17 three-parameter std::hypot()], - [marc_cv_cxx_3_param_std_hypot_supported],[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include - ]], - [[ -double h = std::hypot(3, 4, 5); - ]]) - ], - [ - marc_cv_cxx_3_param_std_hypot_supported=yes - ], - [ - marc_cv_cxx_3_param_std_hypot_supported=no - ]) - ]) - -AS_IF([test "x$marc_cv_cxx_3_param_std_hypot_supported" = "xyes"], - [AC_DEFINE([MARC_HAS_3_PARAM_STD_HYPOT])]) +AS_IF([test "x$marc_cv_lib_fmt" = "xyes"], + [], + [AC_MSG_WARN([fmt library not found, or is it old - using fallback]) + FMTLIB_CPPFLAGS="-I\$(top_srcdir)/opt/fmt-5.2.1/include" + AC_SUBST([FMTLIB_CPPFLAGS]) + ]) dnl Checks for header files. AC_HEADER_STDC @@ -211,8 +208,8 @@ AS_IF([test "x$ax_enable_debug" != "xyes"], [AX_APPEND_FLAG([$marc_lto_flag], [XCXXFLAGS])]) - dnl NDEBUG is defined in but also define it on - dnl the command line to avoid having to include + dnl NDEBUG is defined in but also define it on + dnl the command line to avoid having to include dnl in MaRC headers or template code. dnl AX_APPEND_FLAG([-DNDEBUG], [XCPPFLAGS]) ]) @@ -244,7 +241,7 @@ AC_CONFIG_FILES([ Makefile doc/Makefile lib/Makefile - lib/MaRC/Makefile + lib/marc/Makefile src/Makefile tests/Makefile ]) diff --git a/doc/MaRC_input.texi b/doc/MaRC_input.texi index 834d82b0..b292e633 100644 --- a/doc/MaRC_input.texi +++ b/doc/MaRC_input.texi @@ -440,10 +440,12 @@ does @strong{NOT} modify the data being stored in the output file in anyway. It may, however, cause other applications that read the output file to transform the data to their true/physical values. The @code{DATA_OFFSET} entry must be entered immediately before the -@code{DATA_SCALE} entry. Immediately following these two keywords is -the @code{DATA_TYPE} keyword. The @code{DATA_TYPE} keyword is -required. It specifies the number format that the mapped data will be -stored as. Available data types are: +@code{DATA_SCALE} entry. + +Immediately following these two keywords is the @code{DATA_TYPE} +keyword. The @code{DATA_TYPE} keyword is optional. It specifies the +number format that the mapped data will be stored as. Available data +types are: @cindex @code{DATA_TYPE} @cindex @code{BYTE} @cindex @code{SHORT} @@ -476,15 +478,16 @@ stored as. Available data types are: @noindent -Be aware, for example, that a @code{DOUBLE} type map will occupy four -times as much memory and storage space then a @code{SHORT} type map of -the same dimensions. An example of how all three keywords are used -follows: +A @code{DATA_TYPE} will be automatically chosen based on the type of +images being mapped if one is not specified. Be aware, for example, +that a @code{DOUBLE} type map will occupy four times as much space +then a @code{SHORT} type map of the same dimensions. An example of +how all three keywords are used follows: @example DATA_OFFSET: -1.3 # This is optional. The default is zero. DATA_SCALE: 0.0001 # This is optional. The default is one. -DATA_TYPE: SHORT # This is required. +DATA_TYPE: SHORT # This is optional. @end example @node Lat/Lon Grid, Projections, Output Data, Input Files @@ -508,8 +511,8 @@ between grid points is 10 degrees (planetocentric where applicable @cindex @code{GRID_INTERVAL} @example -GRID: YES # This is required. Enter "YES" or "NO." -GRID_INTERVAL: 5 # This is optional. +GRID: YES # This is optional. "YES" or "NO". "NO" by default. +GRID_INTERVAL:5 # This is optional. Requires GRID. @end example @noindent @@ -1291,17 +1294,17 @@ similarly for longitudes. It is possible to map data using either planetocentric or planetographic latitudes. Also, latitude and longitude ranges to be mapped can also be specified. @cindex @code{LATITUDE_TYPE} -@cindex @code{CENTRIC_LAT} -@cindex @code{GRAPHIC_LAT} +@cindex @code{CENTRIC} +@cindex @code{GRAPHIC} @cindex @code{LO_LAT} @cindex @code{HI_LAT} @cindex @code{LO_LON} @cindex @code{HI_LON} The latitude type is set using the @code{LATITUDE_TYPE} keyword. To choose a planetocentric latitude map, the keyword token -@code{@w{CENTRIC_LAT}} is used. Planetographic latitudes are selected by -using the @code{GRAPHIC_LAT} keyword token. The latitude range is set -by using the @code{LO_LAT} and @code{HI_LAT} keywords, while the +@code{@w{CENTRIC}} is used. Planetographic latitudes are selected by +using the @code{GRAPHIC} keyword token. The latitude range is set by +using the @code{LO_LAT} and @code{HI_LAT} keywords, while the longitude range is set by using the @code{LO_LON} and @code{HI_LON} keywords. The latitude and longitude options as described earlier (@pxref{Angle & Range}) also hold for these latitude/longitude range @@ -1318,7 +1321,7 @@ a MaRC input file: TYPE: SIMPLE_C OPTIONS: AVERAGING: UNWEIGHTED - LATITUDE_TYPE: GRAPHIC_LAT # or CENTRIC_LAT + LATITUDE_TYPE: GRAPHIC # or CENTRIC LO_LAT: 38 S # CENTRIC lat. by default HI_LAT: 8 S LO_LON: 282 W @@ -1383,16 +1386,18 @@ plane entry immediately following the previous entry. Each map plane entry contains an optional range of valid values that can be mapped and a description of what is being mapped. A plane entry begins with the @code{PLANE} keyword. Following this is the optional entry for -the valid data range. The data range is specified by the -@code{DATA_MIN} and @code{DATA_MAX} keywords. All data greater than -or equal to @code{DATA_MIN} and less than or equal to @code{DATA_MAX} -will be mapped. If one or both of these keywords are not specified -then they are assigned the lowest and highest possible values a given +the valid physical data range. The physical data range is specified +by the @code{DATA_MIN} and @code{DATA_MAX} keywords. All physical +data greater than or equal to @code{DATA_MIN} and less than or equal +to @code{DATA_MAX} will be mapped. If one or both of these keywords +are not specified, and an appropriate default cannot be chosen, then +they are assigned the lowest and highest possible values a given platform may have for double precision floating point numbers (usually -on the order of 1E+300 or more), respectively. ``Data'' in this case -refers to values being mapped @emph{after} any scaling and offsets -have been applied. Here is an example of the beginning of a plane -entry: +on the order of 1E+300 or more), respectively. ``Physical data'' in +this case refers to values being mapped @emph{after} any scaling and +offsets have been applied, i.e. physical values (e.g. degrees) as +opposed to array values. Here is an example of the beginning of a +plane entry: @example PLANE: @@ -2000,7 +2005,7 @@ In cases where course-grained map grids (@pxref{Lat/Lon Grid}) are not suitable, MaRC can create maps of the latitudes and longitudes in degrees for each valid pixel on the chosen map projection. Unlike map grids that are considered image extensions, latitude and longitude -planes will placed in the primary map itself. +planes will be placed in the primary map itself. To create a map of latitudes a map plane entry such as the following can be used: @@ -2024,34 +2029,38 @@ LONGITUDE @cindex emission angle @cindex incidence angle @cindex phase angle -The emission angle is the angle between the observer and the normal at a -given point on the body. The incidence angle is the angle between the -sun and the normal at a given point on the body. The phase angle is the -angle between the observer and the sun, where a given point on the -surface of the body is the vertex. All computations involving these -angles take into account the distance between the observer and the body. -The sun is assumed to be an infinite distance away. Here is an example -of how to specify the use of the cosines of the incidence angles in the -plane entry: +The emission angle is the angle between the observer and the normal at +a given point on the body. The incidence angle is the angle between +the sun and the normal at a given point on the body. The phase angle +is the angle between the observer and the sun, where a given point on +the surface of the body is the vertex. Emission and phase angle +calculations take into account the distance between the observer and +the point on the body. The sun is assumed to be an infinite distance +away when calculating incidence and phase angles. + +Rather than map the angles themselves, MaRC will instead map the +corresponding cosines of the emission, incidence and phase angles, +@emph{mu}, @emph{mu0}, and @emph{cos(phi)}, respectively. Here +is an example of how to specify each of the cosine map plane entries: @example -MU0: SUB_OBSERV_LAT: 3.62 S - SUB_OBSERV_LON: 14.45 E - RANGE: 1819712.917 KM - SUB_SOLAR_LAT: -1.80 - SUB_SOLAR_LON: 65.07 E +# Cosines of emission angles +MU: SUB_OBSERV_LAT: -3.62 + SUB_OBSERV_LON: 14.45 E + RANGE: 1819712.917 KM + +# Cosines of incidence angles +MU0: SUB_SOLAR_LAT: -1.80 + SUB_SOLAR_LON: 65.07 E + +# Cosines of phase angles +PHASE: SUB_OBSERV_LAT: 3.62 S + SUB_OBSERV_LON: 14.45 E + RANGE: 1819712.917 KM + SUB_SOLAR_LAT: -1.80 + SUB_SOLAR_LON: 65.07 E @end example -@noindent -To specify one of the other angles, simply replace @code{MU0} with -@code{MU} or @code{PHASE}. Note that all three types of angle entries -require the sub-observation point, the observer range and the sub-solar -point to be specified. This is more for the sake of consistency rather -than necessity (e.g. the observer range isn't need to compute incidence -angles). These were described in the image entry section (@pxref{Image -Geometry}). Although the sub-observer point and the observer range are -not needed to compute the incidence angles, they are used to force the -user to be consistent when entering other angle entries. @node Plane Entry, , Virtual Images, Map Planes @comment node-name, next, previous, up @@ -2110,7 +2119,7 @@ or: @example PLANE: - LATITUDE: LATITUDE_TYPE: GRAPHIC_LAT + LATITUDE: LATITUDE_TYPE: GRAPHIC PLANE: LONGITUDE PLANE: @@ -2141,7 +2150,7 @@ XCOMMENT:Latitude/Longitude grid for this map. TYPE: SIMPLE_C OPTIONS: AVERAGING: UNWEIGHTED - LATITUDE_TYPE: GRAPHIC_LAT + LATITUDE_TYPE: GRAPHIC LO_LAT: -38 # CENTRIC is default HI_LAT: -8 LO_LON: 282 # West since prograde @@ -2245,14 +2254,9 @@ XCOMMENT:Latitude/Longitude grid for this map. SUB_OBSERV_LON: 14.45 E # RANGE defaults to units of Kilometers RANGE: 1819712.917 - SUB_SOLAR_LAT: -1.80 - SUB_SOLAR_LON: 65.07 E PLANE: - MU0: SUB_OBSERV_LAT: 3.62 S - SUB_OBSERV_LON: 14.45 E - RANGE: 1819712.917 KM - SUB_SOLAR_LAT: -1.80 + MU0: SUB_SOLAR_LAT: -1.80 SUB_SOLAR_LON: 65.07 E # The next map in the input file follows. @@ -2281,13 +2285,8 @@ XCOMMENT:Latitude / Longitude grid for primary array (the cube) MU: SUB_OBSERV_LAT: -2.83 SUB_OBSERV_LON: 56.46 E RANGE: 1555114.417 KM - SUB_SOLAR_LAT: -1.80 - SUB_SOLAR_LON: 65.07 E PLANE: - MU0: SUB_OBSERV_LAT: -2.83 - SUB_OBSERV_LON: 56.46 E - RANGE: 1555114.417 - SUB_SOLAR_LAT: -1.80 + MU0: SUB_SOLAR_LAT: -1.80 SUB_SOLAR_LON: 65.07 E PLANE: PHASE: SUB_OBSERV_LAT: -2.83 diff --git a/doc/examples/101.inp b/doc/examples/101.inp index dc575ba0..d46c20f3 100644 --- a/doc/examples/101.inp +++ b/doc/examples/101.inp @@ -12,7 +12,7 @@ XCOMMENT:Another map comment. DATA_TYPE: SHORT GRID: YES TYPE: SIMPLE_C - OPTIONS: GRAPHIC_LAT + OPTIONS: LATITUDE_TYPE: GRAPHIC LO_LAT: -38 # PlanetoCENTRIC is default HI_LAT: -8 LO_LON: 282 # West since prograde @@ -91,12 +91,7 @@ XCOMMENT:Another map comment. SUB_OBSERV_LON: 14.45 E # RANGE defaults to units of Kilometers RANGE: 1819712.917 - SUB_SOLAR_LAT: -1.80 - SUB_SOLAR_LON: 65.07 E PLANE: - MU0: SUB_OBSERV_LAT: 3.62 S - SUB_OBSERV_LON: 14.45 E - RANGE: 1819712.917 KM - SUB_SOLAR_LAT: -1.80 + MU0: SUB_SOLAR_LAT: -1.80 SUB_SOLAR_LON: 65.07 E diff --git a/lib/MaRC/Constants.h b/lib/MaRC/Constants.h deleted file mode 100644 index 89841609..00000000 --- a/lib/MaRC/Constants.h +++ /dev/null @@ -1,983 +0,0 @@ -// -*- C++ -*- -/** - * @file Constants.h - * - * Mathematical and physical constants and conversion factors - * - * Copyright (C) 1993, 1994, 1995 - * Associated Universities, Inc. Washington DC, USA. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. - * - * Correspondence concerning AIPS++ should be addressed as follows: - * Internet email: aips2-request@nrao.edu. - * Postal address: AIPS++ Project Office - * National Radio Astronomy Observatory - * 520 Edgemont Road - * Charlottesville, VA 22903-2475 USA - * - * - * Conversion from C++ structure to namespace by Ossama Othman - * in November 2003. - * - * Use of C++11 constexpr keyword introduced by Ossama Othman - * in July 2017. - * - * @author Associated Universities, Inc. Washington DC, USA - * @author Ossama Othman - */ - -#ifndef MARC_AIPS_CONSTANTS_H -#define MARC_AIPS_CONSTANTS_H - -/** - * @namespace C - * - * @brief Various mathematical and physical constants. - * - * The conversion factors convert to an internal representation. For - * example, @c C::inch when used as a factor converts from inchs to - * internal units (in this case metres). When used as a divisor it - * converts from internal units to inchs. - * - * @verbatim - * Compound usage accords with conventional dimensional analysis, e.g.: - * - * * Factor to convert seconds to days: - * C::second / C::day - * - * * Factor to convert kilometers to feet: - * (C::kilo * C::metre) / C::foot - * - * * Factor to convert acres to hectares: - * C::acre / (C::hecto * C::are) - * - * * Factor to convert millibars to kilopascals: - * (C::milli * C::bar) / (C::kilo * C::Pascal) - * - * The units used internally are as follows: - * - * angle radian - * solid angle steradian - * time [T] second - * length [L] metre - * mass [M] kilogram - * charge [Q] Coulomb - * luminous intensity [Iv] candela - * amount of substance [N] mole - * - * @endverbatim - * - * For derived quantities such as volume, velocity, force, and power, - * the units are specified in terms of those of the fundamental - * quantities. - * - * @todo Some of these constants are outdated, and should be updated - * with the latest values, such as those found on the NIST Web - * site (https://physics.nist.gov/cuu/Constants/index.html). - * We may also want to remove those that aren't used by MaRC, - * which is the majority of them. - */ -namespace C -{ - // Begin Mathematical constants - - /** - * @name Irrationals - */ - //@{ - - /// sqrt(2) - static constexpr double sqrt2 = 1.4142135623730950488; - - /// sqrt(3) - static constexpr double sqrt3 = 1.7320508075688772935; - - /// 1/sqrt(2) - static constexpr double _1_sqrt2 = 0.70710678118654752440; - - /// 1/sqrt(3) - static constexpr double _1_sqrt3 = 0.57735026918962576451; - - //@} - - /** - *@name Pi and functions thereof - */ - //@{ - /// pi - static constexpr double pi = 3.141592653589793238462643; - - /// 2*pi - static constexpr double _2pi = 6.283185307179586476925286; - - /// pi/2 - static constexpr double pi_2 = 1.570796326794896619231322; - - /// pi/4 - static constexpr double pi_4 = 0.7853981633974483096156608; - - /// 1/pi - static constexpr double _1_pi = 0.3183098861837906715377675; - - /// 2/pi - static constexpr double _2_pi = 0.6366197723675813430755350; - - /// 1/sqrt(pi) - static constexpr double _1_sqrtpi = 0.5641895835477562869480795; - - /// 2/sqrt(pi) - static constexpr double _2_sqrtpi = 1.1283791670955125738961590; - //@} - - /** - * @name e and functions thereof - */ - //@{ - /// e - static constexpr double e = 2.718281828459045235360287; - - /// ln(2) - static constexpr double ln2 = 0.6931471805599453094172321; - - /// ln(10) - static constexpr double ln10 = 2.3025850929940456840179915; - - /// log2(e) - static constexpr double log2e = 1.4426950408889634074; - - /// log10(e) - static constexpr double log10e = 0.4342944819032518276511289; - //@} - - /** - * @name gamma and functions thereof - */ - //@{ - /// gamma - static constexpr double gamma = 0.577215664901532860606512; - - /// ln(gamma) - static constexpr double lngamma = -0.549539312981644822337662; - - /// e**gamma - static constexpr double etogamma = 1.7810724179901979852; - //@} - - // End Mathematical constants - - - /* - * Begin Physical constants, and quantities - * - * References: - * "Explanatory Supplement to the Astronomical Almanac", - * - * "Handbook of Chemistry and Physics", 55th ed. - * Robert C. Weast (Ed), 1974. - * CRC Press Inc. - * ISBN 087819-54-1 - */ - - /** - * @name Fundamental physical constants (SI units) - */ - //@{ - /// velocity of light - static constexpr double c = 2.99792458e+08; - - /// Gravitational constant - static constexpr double Gravity = 6.67259e-11; - - /// Planck's constant - static constexpr double Planck = 6.6260755e-34; - - /// gas constant - static constexpr double GasConst = 8.314510; - /// Avogardo's constant - static constexpr double Avogadro = 6.0221367e+23; - - /// electron charge - static constexpr double qe = 1.60217733e-19; - - /// proton mass - static constexpr double mp = 1.6726231e-27; - - /// proton mass / electron mass - static constexpr double mp_me = 1836.152701; - //@} - - /** - * @name Derived physical constants (SI units) - */ - //@{ - /// magnetic permeability of vacuum - static constexpr double mu0 = 4.0e-7 * C::pi; - - /// electric permittivity of vacuum - static constexpr double epsilon0 = 1.0 / ( C::mu0 * C::c * C::c ); - - /// Planck's constant divided by 2*pi - static constexpr double Planck_2pi = C::Planck / C::_2pi; - - /// atomic mass unit - static constexpr double u = 1.0e-3 / C::Avogadro; - - /// Boltzmann's constant - static constexpr double Boltzmann = C::GasConst / C::Avogadro; - - /// Faraday's constant - static constexpr double Faraday = C::Avogadro * C::qe; - - /// electron mass - static constexpr double me = C::mp / C::mp_me; - - /// classical electron radius - static constexpr double re = 2.8179e-15; - - /// Bohr radius - static constexpr double a0 = 5.2918e-11; - //@} - - /** - * @name Physical quantities (SI units) - */ - //@{ - /// solar radius - static constexpr double R0 = 6.9599e+08; - //@} - - // End Physical constants, and quantities - - - // Begin Physical units - - /** - * @name Numerical conversion factors - */ - //@{ - /// e+24 (Y) - static constexpr double yotta = 1.0e+24; - - /// e+21 (Z) - static constexpr double zetta = 1.0e+21; - - /// e+18 (E) - static constexpr double exa = 1.0e+18; - - /// e+15 (P) - static constexpr double peta = 1.0e+15; - - /// e+12 (T) - static constexpr double tera = 1.0e+12; - - /// e+09 (G) - static constexpr double giga = 1.0e+09; - - /// e+06 (M) - static constexpr double mega = 1.0e+06; - - /// e+03 (k) - static constexpr double kilo = 1.0e+03; - - /// e+02 (h) - static constexpr double hecto = 1.0e+02; - - /// e+01 (D) - static constexpr double deka = 1.0e+01; - - /// e-01 (d) - static constexpr double deci = 1.0e-01; - - /// e-02 (c) - static constexpr double centi = 1.0e-02; - - /// e-03 (m) - static constexpr double milli = 1.0e-03; - - /// e-06 (u) - static constexpr double micro = 1.0e-06; - - /// e-09 (n) - static constexpr double nano = 1.0e-09; - - /// e-12 (p) - static constexpr double pico = 1.0e-12; - - /// e-15 (f) - static constexpr double femto = 1.0e-15; - - /// e-18 (a) - static constexpr double atto = 1.0e-18; - - /// e-21 (z) - static constexpr double zepto = 1.0e-21; - - /// e-24 (y) - static constexpr double yocto = 1.0e-24; - //@} - - /** - * @name Angular measure - */ - //@{ - /// radian - static constexpr double radian = 1.0; - - /// circle - static constexpr double circle = (2.0 * C::pi) * C::radian; - - /// circuit - static constexpr double circuit = C::circle; - - /// cycle - static constexpr double cycle = C::circle; - - /// revolution - static constexpr double rev = C::circle; - - /// revolution - static constexpr double revolution = C::circle; - - /// rotation - static constexpr double rotation = C::circle; - - /// degree - static constexpr double degree = (1.0 / 360.0) * C::circle; - - /// arcminute - static constexpr double arcmin = (1.0 / 60.0) * C::degree; - - /// arcsecond - static constexpr double arcsec = (1.0 / 60.0) * C::arcmin; - - /// grad - static constexpr double grad = (1.0 / 400.0) * C::circle; - //@} - - /** - * Solid angular measure - */ - //@{ - /// steradian - static constexpr double steradian = 1.0; - - /// sphere - static constexpr double sphere = (4.0 * C::pi) * C::steradian; - - /// square degree - static constexpr double square_degree = C::degree * C::degree; - - /// square arcminute - static constexpr double square_arcmin = C::arcmin * C::arcmin; - - /// square arcsecond - static constexpr double square_arcsec = C::arcsec * C::arcsec; - //@} - - // End Numerical conversion factors - - - // Begin Physical conversion factors - - /** - * @name Time interval [T] - */ - //@{ - /// second - static constexpr double second = 1.0; - - /// minute - static constexpr double minute = 60.0 * C::second; - - /// hour - static constexpr double hour = 60.0 * C::minute; - - /// day - static constexpr double day = 24.0 * C::hour; - - /// week - static constexpr double week = 7.0 * C::day; - - /// fortnight - static constexpr double fortnight = 2.0 * C::week; - //@} - - /** - * @nameFrequency [1/T] - */ - //@{ - /// Hertz - static constexpr double Hertz = 1.0 / C::second; - //@} - - /** - * @name Length [L] - */ - //@{ - /// metre - static constexpr double metre = 1.0; - - /// metre (American spelling) - static constexpr double meter = C::metre; - - /// Fermi - static constexpr double Fermi = 1.0e-15 * C::metre; - - /// Angstrom - static constexpr double Angstrom = 1.0e-10 * C::metre; - - /// inch - static constexpr double inch = 2.54e-2 * C::metre; - - /// thou (inch/1000) - static constexpr double thou = 1.0e-3 * C::inch; - - /// hand - static constexpr double hand = 4.0 * C::inch; - - /// span - static constexpr double span = 9.0 * C::inch; - - /// foot - static constexpr double foot = 12.0 * C::inch; - - /// yard - static constexpr double yard = 3.0 * C::foot; - - /// fathom - static constexpr double fathom = 6.0 * C::foot; - - /// rod - static constexpr double rod = 16.5 * C::foot; - - /// perch - static constexpr double perch = C::rod; - - /// rope - static constexpr double rope = 20.0 * C::foot; - - /// chain - static constexpr double chain = 22.0 * C::yard; - - /// furlong - static constexpr double furlong = 220.0 * C::yard; - - /// English statute mile - static constexpr double mile = 5280.0 * C::foot; - - /// nautical mile - static constexpr double nautical_mile = 6080.0 * C::foot; - - /// point - static constexpr double point = (1.0 / 72.0) * C::inch; - - /// pica - static constexpr double pica = 12.0 * C::point; - - /// astronomical unit - static constexpr double astronomical_unit = 1.4959787066e+11 * C::metre; - - /// light second - static constexpr double light_second = C::c * C::metre; - - /// light year - static constexpr double light_year = 9.46073047e+15 * C::metre; - - /// parsec - static constexpr double parsec = 3.26156378 * C::light_year; - //@} - - /** - * @name Area [L*L] - */ - //@{ - /// square metre - static constexpr double square_metre = C::metre * C::metre; - - /// square meter (American spelling) - static constexpr double square_meter = C::square_metre; - - /// are - static constexpr double are = 100.0 * C::square_metre; - - /// barn - static constexpr double barn = 1.0e-28 * C::square_metre; - - /// square inch - static constexpr double square_inch = C::inch * C::inch; - - /// square foot - static constexpr double square_foot = C::foot * C::foot; - - /// square yard - static constexpr double square_yard = C::yard * C::yard; - - /// square mile - static constexpr double square_mile = C::mile * C::mile; - - /// square perch - static constexpr double square_perch = C::perch * C::perch; - - /// rood - static constexpr double rood = 40.0 * C::square_perch; - - /// acre - static constexpr double acre = 4.0 * C::rood; - - /// square - static constexpr double square = 100.0 * C::square_foot; - //@} - - /** - * @name Volume [L*L*L] - */ - //@{ - /// cubic metre - static constexpr double cubic_metre = C::metre * C::square_metre; - - /// cubic meter (American spelling) - static constexpr double cubic_meter = C::cubic_metre; - - /// stere - static constexpr double stere = C::cubic_metre; - - /// litre - static constexpr double litre = 1.0e-3 * C::cubic_metre; - - /// liter (American spelling) - static constexpr double liter = C::litre; - - /// cubic inch - static constexpr double cubic_inch = C::inch * C::square_inch; - - /// cubic foot - static constexpr double cubic_foot = C::foot * C::square_foot; - - /// cubic yard - static constexpr double cubic_yard = C::yard * C::square_yard; - - /// cubic mile - static constexpr double cubic_mile = C::mile * C::square_mile; - - /// (Brit) gallon - static constexpr double gallon = 277.4193 * C::cubic_inch; - - /// (Brit) quart - static constexpr double quart = (1.0 / 4.0) * C::gallon; - - /// (Brit) pint - static constexpr double pint = (1.0 / 2.0) * C::quart; - - /// (Brit) gill - static constexpr double gill = (1.0 / 4.0) * C::pint; - - /// (Brit) fluid ounce - static constexpr double fluid_ounce = (1.0 / 5.0) * C::gill; - - /// (Brit) drachm - static constexpr double drachm = (1.0 / 8.0) * C::fluid_ounce; - - /// (Brit) scruple - static constexpr double scruple = (1.0 / 3.0) * C::drachm; - - /// (Brit) minim - static constexpr double minim = (1.0 / 20.0) * C::scruple; - - /// (US liq) gallon - static constexpr double USgallon = 231.0 * C::cubic_inch; - - /// (US liq) quart - static constexpr double USquart = (1.0 / 4.0) * C::USgallon; - - /// (US liq) pint - static constexpr double USpint = (1.0 / 2.0) * C::USquart; - - /// (US liq) gill - static constexpr double USgill = (1.0 / 4.0) * C::USpint; - - /// (US liq) fluid ounce - static constexpr double USfluid_ounce = (1.0 / 4.0) * C::USgill; - - /// (US liq) dram - static constexpr double USdram = (1.0 / 8.0) * C::USfluid_ounce; - - /// (US liq) minim - static constexpr double USminim = (1.0 / 60.0) * C::USdram; - //@} - - /** - * @name Speed [L/T] - */ - //@{ - /// nautical miles per hour - static constexpr double knot = C::nautical_mile / C::hour; - //@} - - /** - * @name Acceleration (speed / time) [L/(T*T)] - */ - //@{ - /// gravitational acceleration - static constexpr double g = 9.80665 * C::metre / C::second / C::second; - //@} - - /** - * @name Mass [M] - */ - //@{ - /// gram - static constexpr double gram = 0.001; - - /// metric ton - static constexpr double tonne = 1000.0 * C::kilo * C::gram; - - /// metric carat - static constexpr double carat = (1.0 / 5.0) * C::gram; - - /// pound (avoirdupois) - static constexpr double pound = 0.45359237 * C::kilo * C::gram; - - /// ounce (avoirdupois) - static constexpr double ounce = (1.0 / 16.0) * C::pound; - - /// stone - static constexpr double stone = 14.0 * C::pound; - - /// stone - static constexpr double quarter = 2.0 * C::stone; - - /// (long) hundredweight - static constexpr double hundredweight = 4.0 * C::quarter; - - /// (long) ton - static constexpr double ton = 20.0 * C::hundredweight; - - /// cental - static constexpr double cental = 100.0 * C::pound; - - /// short quarter (Brit) - static constexpr double shortquarter = 25.0 * C::pound; - - /// short hundredweight - static constexpr double shortcwt = 4.0 * C::shortquarter; - - /// short ton - static constexpr double shortton = 20.0 * C::shortcwt; - //@} - - /** - * @name Force (mass * acceleration) [M*L/(T*T)] - */ - //@{ - - /// Newton - static constexpr double Newton = - C::kilo * C::gram * C::metre / C::second / C::second; - - /// dyne - static constexpr double dyne = 1.0e-5 * C::Newton; - //@} - - /** - * @name Pressure (force / area) [M/(L*T*T)] - */ - //@{ - /// Pascal - static constexpr double Pascal = C::Newton / C::square_metre; - - /// atmosphere - static constexpr double atmosphere = 1.01325e+5 * C::Pascal; - - /// bar - static constexpr double bar = 1.0e+5 * C::Pascal; - - /// torr - static constexpr double torr = (1.0 / 760.0) * C::atmosphere; - - /// mm of Mercury - static constexpr double mmHg = (13.5951 * C::g) * C::Pascal; - //@} - - /** - * @name Energy (force * length) [M*L*L/(T*T)] - */ - //@{ - /// Joule - static constexpr double Joule = C::Newton * C::metre; - - /// kiloWatt * hour - static constexpr double kWh = 3.6e+6 * C::Joule; - - /// erg - static constexpr double erg = 1.0e-7 * C::Joule; - - /// calorie (thermochemical) - static constexpr double calorie = 4.184 * C::Joule; - - /// calorie (International Steam) - static constexpr double calorie_IT = 4.1868 * C::Joule; - - /// British thermal unit - static constexpr double Btu = 1.05435e+3 * C::Joule; - - /// electron volt - static constexpr double eV = C::qe * C::Joule; - //@} - - /** - * @name Temperature difference (energy) [M*L*L/(T*T)] - */ - //@{ - /// Kelvin - static constexpr double Kelvin = C::Boltzmann * C::Joule; - - /// Celsius - static constexpr double Celsius = C::Kelvin; - - /// Centigrade - static constexpr double Centigrade = C::Celsius; - - /// Fahrenheit - static constexpr double Fahrenheit = (5.0 / 9.0) * C::Kelvin; - - /// Rankine - static constexpr double Rankine = C::Fahrenheit; - //@} - - /** - * @name Temperature at 0 on each temperature scale - */ - //@{ - /// Absolute Zero (Kelvins) - static constexpr double Kelvin_0 = 0.0 * C::Kelvin; - - /// Celsius Zero - static constexpr double Celsius_0 = 273.15 * C::Kelvin; - - /// Centigrade Zero - static constexpr double Centigrade_0 = C::Celsius_0; - - /// Fahrenheit Zero - static constexpr double Fahrenheit_0 = 459.67 * C::Fahrenheit; - - /// Absolute Zero (Rankines) - static constexpr double Rankine_0 = 0.0 * C::Fahrenheit; - //@} - - /** - * @name Power (energy / time) [M*L*L/(T*T*T)] - */ - //@{ - /// Watt - static constexpr double Watt = C::Joule / C::second; - - /// horsepower - static constexpr double horsepower = 745.7 * C::Watt; - //@} - - /** - * @name Flux density (power / area / frequency) [M/(T*T)] - */ - //@{ - /// Jansky - static constexpr double Jansky = 1.0e-26 * C::Watt / C::square_metre / C::Hertz; - - /// flux units - static constexpr double fu = C::Jansky; - //@} - - /** - * @name Electric charge [Q] (Coulomb) - */ - //@{ - /// Coulomb - static constexpr double Coulomb = 1.0; - - /// abCoulomb (emu) - static constexpr double abCoulomb = 10.0 * C::Coulomb; - - /// statCoulomb (esu) - static constexpr double statCoulomb = (0.1 / C::c) * C::Coulomb; - //@} - - /** - * @name Electric current (charge / time) [Q/T] - */ - //@{ - /// Ampere - static constexpr double Ampere = C::Coulomb / C::second; - - /// abAmpere (emu) - static constexpr double abAmpere = 10.0 * C::Ampere; - - /// statAmpere (esu) - static constexpr double statAmpere = (0.1 / C::c) * C::Ampere; - //@} - - // Electric field strength (force / charge) [M*L/(T*T*Q)] - - /** - * @name Electric potential (energy / charge) [M*L*L/(T*T*Q)] - */ - //@{ - /// Volt - static constexpr double Volt = C::Joule / C::Coulomb; - - /// abVolt (emu) - static constexpr double abVolt = 1.0e-8 * C::Volt; - - /// statVolt (esu) - static constexpr double statVolt = (C::c * 1.0e-6) * C::Volt; - //@} - - /** - * @name Electric resistance (potential / current) [M*L*L/(T*Q*Q)]] - */ - //@{ - /// Ohm - static constexpr double Ohm = C::Volt / C::Ampere; - - /// abOhm (emu) - static constexpr double abOhm = 1.0e-9 * C::Ohm; - - /// starOhm (esu) - static constexpr double statOhm = (3.0e+3 * C::c) * C::Ohm; - //@} - - /** - * @name Electric conductance (current / potential) [T*Q*Q/(M*L*L)] - */ - //@{ - /// Siemens - static constexpr double Siemens = C::Ampere / C::Volt; - - /// mho - static constexpr double mho = C::Siemens; - //@} - - /** - * @name Electric capacitance (charge / potential) [T*T*Q*Q/(M*L*L)] - */ - //@{ - /// Farad - static constexpr double Farad = C::Coulomb / C::Volt; - - /// abFarad (emu) - static constexpr double abFarad = 1.0e+9 * C::Farad; - - /// statFarad (esu) - static constexpr double statFarad = 1.0 / (3.0e+3 * C::c) * C::Farad; - //@} - - /** - * @name Electric inductance (potential * time / current) [M*L*L/(Q*Q)] - */ - //@{ - /// Henry - static constexpr double Henry = C::Volt * C::second / C::Ampere; - - /// abHenry (emu) - static constexpr double abHenry = 1.0e-9 * C::Henry; - - /// statHenry (esu) - static constexpr double statHenry = (3.0e+3 * C::c) * C::Henry; - //@} - - /** - * @name Magnetic induction (force / charge / velocity) [M/(T*Q)] - */ - //@{ - /// Tesla - static constexpr double Tesla = C::Newton / C::Coulomb / (C::metre / C::second); - - /// Gauss (emu) - static constexpr double Gauss = 1.0e-4 * C::Tesla; - //@} - - /** - * @name Magnetic flux (magnetic induction * area) [M*L*L/(T*Q)] - */ - //@{ - /// Weber - static constexpr double Weber = C::Tesla / C::square_metre; - - /// Maxwell (emu) - static constexpr double Maxwell = 1.0e-8 * C::Weber; - - /// line (emu) - static constexpr double line = C::Maxwell; - //@} - - /** - * @name Magnetomotance = magnetomotive force (current) [Q/T] - */ - //@{ - /// Ampere-turn - static constexpr double Ampere_turn = C::Ampere; - - /// abAmpere-turn - static constexpr double abAmpere_turn = 10.0 * C::Ampere_turn; - - /// Gilbert (emu) - static constexpr double Gilbert = 10.0 / (4.0 * C::pi) * C::Ampere_turn; - - /// praGilbert (emu) - static constexpr double praGilbert = (4.0 * C::pi) * C::Ampere_turn; - //@} - - // Magnetic field intensity (current / length) [Q/(T*L)]: - //@{ - /// Oersted (emu) - static constexpr double Oersted = 1000.0 / (4.0 * C::pi) * C::Ampere / C::metre; - - /// praOersted (emu) - static constexpr double praOersted = (4.0 * C::pi) * C::Ampere / C::metre; - //@} - - /** - * @name Radioactivity (Bequerel) - */ - //@{ - /// Bequerel - static constexpr double Bequerel = 1.0; - //@} - - /** - * @name Luminous intensity [Iv] - */ - //@{ - /// candela - static constexpr double candela = 1.0; - //@} - - /** - * @name Amount of substance [N] - */ - //@{ - /// mole - static constexpr double mole = 1.0; - - /// number of molecules - static constexpr double molecule = (1.0 / C::Avogadro) * C::mole; - //@} - - // End Physical conversion factors - - // End Physical units - -} - -#endif /* MARC_AIPS_CONSTANTS_H */ diff --git a/lib/MaRC/Log.cpp b/lib/MaRC/Log.cpp deleted file mode 100644 index 3ffd3674..00000000 --- a/lib/MaRC/Log.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -*- C++ -*- -/** - * @file Log.cpp - * - * Copyright (C) 2018 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -#include "Log.h" -#include "config.h" - - -namespace { - auto init_marc_logger() - { - auto logger = spdlog::stdout_color_mt(PACKAGE); - - // No need for a date and time stamp for console logging at - // this point in time. - // [logger name] [log level] text to log - logger->set_pattern("[%n] [%l] %v"); - -#ifndef NDEBUG - logger->set_level(spdlog::level::debug); -#endif // NDEBUG - - return logger; - } -} - -namespace MaRC -{ - logger_type const _logger = init_marc_logger(); -} diff --git a/lib/MaRC/Log.h b/lib/MaRC/Log.h deleted file mode 100644 index 33f76d68..00000000 --- a/lib/MaRC/Log.h +++ /dev/null @@ -1,150 +0,0 @@ -// -*- C++ -*- -/** - * @file Log.h - * - * MaRC logging interface. - * - * Copyright (C) 2018 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -/** - * @todo Ideally we shouldn't have to include this header since the - * underlying MaRC logger instance shouldn't be exposed to the - * user. - */ -#include "MaRC/Export.h" // For MARC_API - -/** - * @bug We really shouldn't be exposing to the user - * since it contains preprocessor symbols that pollute the global - * namespace. - */ -#include "MaRC/config.h" // For NDEBUG - -/** - * Enable debug and trace level logging in spdlog. - * - * @note @c NDEBUG should be defined on the command line if debug - * logging should be disabled so that including "MaRC/config.h" - * and exposing as part of the user interface can be avoided. - */ -#ifdef NDEBUG -# define MARC_DEBUG_ARGS(x) -#else -# define SPDLOG_DEBUG_ON -# define MARC_DEBUG_ARGS(x) x -#endif // NDEBUG - -#include - - -namespace MaRC -{ - /** - * @typedef Underlying logger type. - * - * @note Not meant for use outside of MaRC. - */ - using logger_type = std::shared_ptr; - - /** - * @internal Pointer to the underlying MaRC logger. - * - * @todo This isn't a good way to expose the MaRC logger - * instance since it isn't meant to be part of the MaRC - * API. - */ - extern MARC_API logger_type const _logger; - - /** - * @brief Log debugging messages. - * - * @param[in] args Log arguments formatted according to the @c fmt - * library. - * - * @see http://fmtlib.net/latest/index.html - */ - template - void - debug(Args const & ... MARC_DEBUG_ARGS(args)) - { - SPDLOG_DEBUG(_logger, args ...); - } - - /** - * @brief Log information messages. - * - * @param[in] args Log arguments formatted according to the @c fmt - * library. - * - * @see http://fmtlib.net/latest/index.html - */ - template - void - info(Args const & ... args) - { - _logger->info(args ...); - } - - /** - * @brief Log warning messages. - * - * @param[in] args Log arguments formatted according to the @c fmt - * library. - * - * @see http://fmtlib.net/latest/index.html - */ - template - void - warn(Args const & ... args) - { - _logger->warn(args ...); - } - - /** - * @brief Log error messages. - * - * @param[in] args Log arguments formatted according to the @c fmt - * library. - * - * @see http://fmtlib.net/latest/index.html - */ - template - void - error(Args const & ... args) - { - _logger->error(args ...); - } - - /** - * @brief Log critical messages. - * - * @param[in] args Log arguments formatted according to the @c fmt - * library. - * - * @see http://fmtlib.net/latest/index.html - */ - template - void - critical(Args const & ... args) - { - _logger->critical(args ...); - } -} diff --git a/lib/MaRC/Version.cpp b/lib/MaRC/Version.cpp deleted file mode 100644 index 7d6c6055..00000000 --- a/lib/MaRC/Version.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file Version.cpp - * - * MaRC library version information. - * - * Copyright (C) 2017 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -#include "Version.h" -#include "config.h" - - -char const * MaRC::library_version() -{ - return PACKAGE_VERSION; -} diff --git a/lib/MaRC/Version.h b/lib/MaRC/Version.h deleted file mode 100644 index c8d4b654..00000000 --- a/lib/MaRC/Version.h +++ /dev/null @@ -1,50 +0,0 @@ -// -*- C++ -*- -/** - * @file Version.h - * - * MaRC library version information. - * - * Copyright (C) 2017 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -#ifndef MARC_LIB_VERSION_H -#define MARC_LIB_VERSION_H - -#include "MaRC/Export.h" - - -namespace MaRC -{ - /** - * @brief Get MaRC library version. - * - * @todo Remove this function. It doesn't serve a useful purpose, - * particularly library versioning is introduced. - * - * @deprecated This function will be removed soon. Do not use - * it. - * - * @return String containing the MaRC library version. - */ - MARC_API char const * library_version(); -} - - -#endif /* MARC_LIB_VERSION_H */ diff --git a/lib/MaRC/VirtualImage.h b/lib/MaRC/VirtualImage.h deleted file mode 100644 index a0fa1022..00000000 --- a/lib/MaRC/VirtualImage.h +++ /dev/null @@ -1,391 +0,0 @@ -// -*- C++ -*- -/** - * @file VirtualImage.h - * - * Copyright (C) 2003-2004, 2017-2018 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -#ifndef MARC_VIRTUAL_IMAGE_H -#define MARC_VIRTUAL_IMAGE_H - -#include "MaRC/SourceImage.h" -#include - -#include -#include - - -namespace MaRC -{ - /** - * @brief Integer data scale and offset calculation functor. - * - * Determine the best scale and offset parameters applied to - * floating point data read from source images to retain as many - * significant digits as possible when storing that data in - * integer typed maps. - * - * @see MaRC::scale_and_offset() - * - * @note This functor is not part of the public MaRC library API. - */ - template - struct scale_and_offset_impl - { - bool operator()(double min, - double max, - double & scale, - double & offset) const - { - constexpr auto T_lowest = std::numeric_limits::lowest(); - constexpr auto T_max = std::numeric_limits::max(); - - static_assert( - T_lowest >= std::numeric_limits::lowest() / 2 - && T_max <= std::numeric_limits::max() / 2, - "Integer type is too large for scale/offset calculation"); - - /* - Avoid integer overflow by performing a floating point - subtraction. No overflow will occur since we already - know: - T_max - T_lowest < std::numeric_limits::max() - */ - constexpr double type_range = - static_cast(T_max) - T_lowest; - - double const data_range = max - min; - - if (!std::isfinite(data_range) - || data_range < 0 - || data_range > type_range) { - // data_range is not a finite value (e.g. overflowed) - // or min > max - // or can't fit all data into desired type T - return false; - } - - int const exponent = - static_cast(std::numeric_limits::digits10) - - static_cast(std::log10(data_range)); - - scale = std::pow(10, exponent); - - if (min * scale < T_lowest) - offset = data_range / 2 * scale; - else if (max * scale > T_max) - offset = -data_range / 2 * scale; - else - offset = 0; - - return true; - } - }; - - /** - * @brief @c float typed data scale and offset calculation - * functor. - * - * Automatic source data scaling is not performed when mapping to - * floating point typed maps. This implementation is basically a - * no-op, and returns @a scale and @a offset values that result in - * the source data remaining unchanged. - * - * @see MaRC::scale_and_offset() - * - * @note This functor is not part of the public MaRC library API. - */ - template <> - struct scale_and_offset_impl - { - bool operator()(double /* min */, - double /* max */, - double & scale, - double & offset) const - { - // No auto-scaling for floating point map data. - scale = 1; - offset = 0; - - return true; - } - }; - - /** - * @brief @c double typed data scale and offset calculation - * functor. - * - * Automatic source data scaling is not performed when mapping to - * floating point typed maps. This implementation is basically a - * no-op, and returns @a scale and @a offset values that result in - * the source data remaining unchanged. - * - * @see MaRC::scale_and_offset() - * - * @note This functor is not part of the public MaRC library API. - */ - template <> - struct scale_and_offset_impl - { - bool operator()(double /* min */, - double /* max */, - double & scale, - double & offset) const - { - // No auto-scaling for floating point map data. - scale = 1; - offset = 0; - - return true; - } - }; - - /** - * @brief Determine suitable data scale and offset values. - * - * Determine the best scale and offset parameters applied to - * floating point data read from source images to retain as many - * significant digits as possible when storing that data in - * integer typed maps. - * - * Some source images, e.g. @c MaRC::VirtualImage subclasses, only - * provide floating point numbers. That is a problem when storing - * those numbers in integer typed maps since significant digits - * after the decimal point could be truncated when casting from - * floating point to integer. To prevent loss of significant - * digits in such cases, the data should be scaled upward and - * potentially offset from their original values so that more - * significant digits end up to the left decimal point prior to - * assignment to elements in integer typed maps. - * - * For example, cosine values to be stored in a 16 bit signed - * integer map could be scaled by 10000 with a zero offset to - * increase the number of significant digits in the map data from - * one to four, e.g. 0.1234567 becomes 1234.567, which ends being - * stored as 1234 in a 16 bit signed integer map. A scale factor - * of 10000 in this case is suitable since the scaled data range, - * -10000 to 10000, never exceeds the 16 bit signed integer data - * range, i.e -32768 to 32767. The chosen scale order of - * magnitude is the largest it can be without causing transformed - * data to exceed the map data range. - * - * To reduce potential confusion about what the data actually is, - * only power of 10 scale factors (i.e. 1, 10, 100, etc) are - * chosen. Unless the data minimum (@a min) and maximum (@a max) - * are not symmetrical and/or the map data type is unsigned, the - * offset value will generally be zero. - * - * The physical data should be transformed according to the - * following equation prior to mapping: - * - * @code - * map_data = scale * physical_data + offset - * @endcode - * - * Retrieving the original physical data from the map would then - * require the following equation: - * - * @code - * physical_data = (map_data - offset) / scale - * @endcode - * - * @note The @a scale and @a offset will always be 1 and 0, - * respectively, if the map data type is a floating point - * type, i.e. @c float or @c double. - * - * @attention This function only generates @a scale and @a offset - * values that allow data to fit within the map data - * range without decreasing the order of magnitude of - * the data, resulting in loss of significant digits. - * In particular, the scale value will always be - * greater than or equal to one if this function - * completes successfully. - * - * @param[in] min The lowest physical value to be plotted on a - * map. For example, this would be -1 for - * source images that generate cosines. - * @param[in] max The highest physical value to be plotted on - * a map. For example, this would be 1 for - * source images that generate cosines. - * @param[out] scale Linear scaling value by which physical data - * should be multiplied to maximize the number - * of significant digits prior to storing data - * in an integer typed map. This will be 1 for - * floating point typed maps. - * @param[out] offset Offset value to be added to data after the - * scaling factor has been applied to force - * that data to fit within the integer typed - * map data range. This will be 0 for floating - * point typed maps. - * - * @retval true Suitable @a scale and @a offset values were - * found. - * @retval false Suitable @a scale and @a offset values were not - * found. This can occur if it isn't possible to - * scale data without loss of significant digits, - * such as when a scale factor less than 1 would be - * required. - */ - template - bool scale_and_offset(double min, - double max, - double & scale, - double & offset) - { - return scale_and_offset_impl()(min, max, scale, offset); - } - - // -------------------------------------------------------------- - - /** - * @class VirtualImage - * - * @brief Base class for virtual source images. - * - * Data from virtual images are computed at run-time rather than - * retrieved from static sources such as images stored on a - * filesystem. - */ - class MARC_API VirtualImage : public SourceImage - { - public: - - /// Constructor. - /** - * @param[in] s Linear scaling coefficient applied to computed - * data. - * @param[in] o Linear offset value applied to all (scaled) - * computed data. - */ - VirtualImage(double s = 1, double o = 0); - - /// Retrieve data from virtual image. - /** - * Retrieve data from virtual image and apply configured data - * transformations, if any. Raw data is computed/retrieved - * from the @c read_data_i() template method. - * - * @param[in] lat Planetocentric latitude in radians. - * @param[in] lon Longitude in radians. - * - * @param[out] data Data retrieved from image. - * - * @retval true Data retrieved - * @retval false No data retrieved. - * - * @see read_data_i() - */ - virtual bool read_data(double lat, - double lon, - double & data) const; - - /** - * @name Linear Data Transformation - * - * These methods return the scale and offset values that - * should be used when linearly transforming data read from a - * @ c VirtualImage and plotted on a map to the true physical - * values. In particular, data should be transformed - * according to the following equation: - * - * @code - * physical_value = map_value * scale() + offset(); - * @endcode - * - * The default implementation returns values that causes no - * transformation to occur. - */ - //@{ - /// Data scale. - /** - * Linear scaling coefficient that should be applied to map - * data to transform that data to true physical data. - * - * @return Data scale. - */ - double scale() const { return 1 / this->scale_; } - - /// Data offset - /** - * Offset value that should be applied to all (scaled) - * computed data. This value corresponds to zero in the - * virtual image. - * - * @return Data offset. - */ - double offset() const { return this->scale() * -this->offset_; } - //@} - - private: - - /// Compute data specific to a given virtual image. - /** - * This template method is the core implementation of the - * @c read_data() method. - * - * @param[in] lat Planetocentric latitude in radians. - * @param[in] lon Longitude in radians. - * - * @param[out] data Data retrieved from image. - * - * @retval true Data retrieved - * @retval false No data retrieved. - * - * @see read_data() - */ - virtual bool read_data_i(double lat, - double lon, - double & data) const = 0; - - private: - - /// Linear scaling coefficient applied to physical data. - /** - * Linear scaling coefficient applied to physical data to - * allow data to fit in map array element of specific type - * with the most amount of significant digits. - * - * @note This is inverse of the of the scaling coefficient - * needed to retrieve the true physical value. - * - * @see @c VirtualImage::scale() - */ - double const scale_; - - /// Offset value applied to scaled physical data. - /** - * This offset is applied to scaled physical data to allow - * data fit in a map array element of specific type with the - * most amount of significant digits. - * - * @note This is the negative offset multiplied by the inverse - * of the of scaling value needed to retrieve the true - * physical value. - * - * @see @c VirtualImage::offset() - */ - double const offset_; - - }; - -} // End MaRC namespace - - -#endif /* MARC_VIRTUAL_IMAGE_H */ diff --git a/lib/MaRC/plot_info.h b/lib/MaRC/plot_info.h deleted file mode 100644 index 712f03c3..00000000 --- a/lib/MaRC/plot_info.h +++ /dev/null @@ -1,112 +0,0 @@ -// -*- C++ -*- -/** - * @file plot_info.h - * - * Copyright (C) 2018 Ossama Othman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * @author Ossama Othman - */ - -#ifndef MARC_PLOT_INFO_H -#define MARC_PLOT_INFO_H - -#include -#include - - -namespace MaRC -{ - class SourceImage; - - /** - * @class plot_info - * - * @brief Map plotting information. - * - * Information that will be used when a plotting a map is - * enscapsulated in this class. - */ - class MARC_API plot_info - { - public: - - using notifier_type = Progress::Notifier; - - /** - * @brief Constructor - * - * @param[in] source @c SourceImage object containing the - * data to be mapped. - * @param[in] minimum Minimum allowed value on map, i.e. all - * data greater than or equal to - * @a minimum. - * @param[in] maximum Maximum allowed value on map, i.e. all - * data less than or equal to @a maximum. - */ - plot_info(SourceImage const & source, - double minimum, - double maximum) - : source_(source) - , minimum_(minimum) - , maximum_(maximum) - , notifier_() - { - } - - ~plot_info() = default; - plot_info(plot_info const &) = delete; - void operator=(plot_info const &) = delete; - - /// Get data to be mapped. - SourceImage const & source() const { return this->source_; } - - /// Get minimum allowed value on map. - double minimum() const { return this->minimum_; } - - /// Get maximum allowed value on map. - double maximum() const { return this->maximum_; } - - /** - * @brief Get map progress notifier. - * - * Use this notifier to subscribe observers for map progress - * notifications. - * - * @see Notifier - */ - notifier_type & notifier() const { return this->notifier_; } - - private: - - /// @c SourceImage object containing the data to be mapped. - SourceImage const & source_; - - /// Minimum allowed value on map, i.e. data >= @c minimum_. - double const minimum_; - - /// Maximum allowed value on map, i.e. data <= @c maximum_. - double const maximum_; - - /// Map progress notifier. - mutable notifier_type notifier_; - - }; - -} // MaRC - -#endif // MARC_PLOT_INFO_H diff --git a/lib/Makefile.am b/lib/Makefile.am index d732b663..79796495 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -17,6 +17,6 @@ ## Process this file with automake to create Makefile.in -SUBDIRS = MaRC +SUBDIRS = marc -DIST_SUBDIRS = MaRC +DIST_SUBDIRS = marc diff --git a/lib/MaRC/BilinearInterpolation.cpp b/lib/marc/BilinearInterpolation.cpp similarity index 98% rename from lib/MaRC/BilinearInterpolation.cpp rename to lib/marc/BilinearInterpolation.cpp index aa4f32d5..b3fe7612 100644 --- a/lib/MaRC/BilinearInterpolation.cpp +++ b/lib/marc/BilinearInterpolation.cpp @@ -1,5 +1,5 @@ /** - * @file BilinearInterpolationStrategy.cpp + * @file BilinearInterpolation.cpp * * Copyright (C) 2003-2004, 2017 Ossama Othman * diff --git a/lib/MaRC/BilinearInterpolation.h b/lib/marc/BilinearInterpolation.h similarity index 92% rename from lib/MaRC/BilinearInterpolation.h rename to lib/marc/BilinearInterpolation.h index 6164ad43..4b3cd4a3 100644 --- a/lib/MaRC/BilinearInterpolation.h +++ b/lib/marc/BilinearInterpolation.h @@ -25,8 +25,8 @@ #ifndef MARC_BILINEAR_INTERPOLATION_H #define MARC_BILINEAR_INTERPOLATION_H -#include "MaRC/InterpolationStrategy.h" -#include "MaRC/Export.h" +#include "marc/InterpolationStrategy.h" +#include "marc/Export.h" #include @@ -35,7 +35,7 @@ namespace MaRC { /** - * @class BilinearInterpolation + * @class BilinearInterpolation BilinearInterpolation.h * * @brief Bilinear interpolation strategy. * @@ -74,7 +74,7 @@ namespace MaRC virtual bool interpolate(double const * data, double x, double z, - double & datum) const; + double & datum) const override; private: diff --git a/lib/MaRC/BodyData.cpp b/lib/marc/BodyData.cpp similarity index 100% rename from lib/MaRC/BodyData.cpp rename to lib/marc/BodyData.cpp diff --git a/lib/MaRC/BodyData.h b/lib/marc/BodyData.h similarity index 97% rename from lib/MaRC/BodyData.h rename to lib/marc/BodyData.h index 1c5ea235..28d98b0e 100644 --- a/lib/MaRC/BodyData.h +++ b/lib/marc/BodyData.h @@ -25,14 +25,14 @@ #ifndef MARC_BODY_DATA_H #define MARC_BODY_DATA_H -#include +#include namespace MaRC { /** - * @class BodyData + * @class BodyData BodyData.h * * @brief Class representing the body under observation. * @@ -54,7 +54,10 @@ namespace MaRC * @param[in] prograde Flag that states whether body rotation * is prograde or retrograde. */ - BodyData(bool prograde); + constexpr BodyData(bool prograde) noexcept + : prograde_(prograde) + { + } // Disallow copying. BodyData(BodyData const &) = delete; diff --git a/lib/marc/Constants.h b/lib/marc/Constants.h new file mode 100644 index 00000000..23ce53c0 --- /dev/null +++ b/lib/marc/Constants.h @@ -0,0 +1,987 @@ +// -*- C++ -*- +/** + * @file Constants.h + * + * @brief Mathematical and physical constants and conversion factors + * + * Copyright (C) 1993, 1994, 1995 + * Associated Universities, Inc. Washington DC, USA. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + * License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. + * + * Correspondence concerning AIPS++ should be addressed as follows: + * Internet email: aips2-request@nrao.edu. + * Postal address: AIPS++ Project Office + * National Radio Astronomy Observatory + * 520 Edgemont Road + * Charlottesville, VA 22903-2475 USA + * + * + * Conversion from C++ structure to namespace by Ossama Othman + * in November 2003. + * + * Use of C++11 constexpr keyword introduced by Ossama Othman + * in July 2017. + * + * Several constants updated from corresponding revised BIPM and IAU + * values by Ossama Othman in November 2018. + * + * @author Associated Universities, Inc. Washington DC, USA + * @author Ossama Othman + */ + +#ifndef MARC_AIPS_CONSTANTS_H +#define MARC_AIPS_CONSTANTS_H + +/** + * @namespace C + * + * @brief Various mathematical and physical constants. + * + * The conversion factors convert to an internal representation. For + * example, @c C::inch when used as a factor converts from inchs to + * internal units (in this case metres). When used as a divisor it + * converts from internal units to inchs. + * + * Compound usage accords with conventional dimensional analysis, e.g.: + * + * * Factor to convert seconds to days: + * ~~~ + * C::second / C::day + * ~~~ + * * Factor to convert kilometers to feet: + * ~~~ + * (C::kilo * C::metre) / C::foot + * ~~~ + * * Factor to convert acres to hectares: + * ~~~ + * C::acre / (C::hecto * C::are) + * ~~~ + * * Factor to convert millibars to kilopascals: + * ~~~ + * (C::milli * C::bar) / (C::kilo * C::Pascal) + * ~~~ + * + * The units used internally are as follows: + * + * Dimension | Symbol | Unit + * ------------------- | :----: | --------- + * angle | | radian + * solid angle | | steradian + * time | T | second + * length | L | metre + * mass | M | kilogram + * charge | Q | Coulomb + * luminous intensity | Iv | candela + * amount of substance | N | mole + * + * For derived quantities such as volume, velocity, force, and power, + * the units are specified in terms of those of the fundamental + * quantities. + * + * @todo Some of these constants are outdated, and should be updated + * with the latest values, such as those found on the NIST Web + * site (https://physics.nist.gov/cuu/Constants/index.html). + * We may also want to remove those that aren't used by %MaRC, + * which is the majority of them. + */ +namespace C +{ + // Begin Mathematical constants + + /** + * @name Irrationals + */ + //@{ + /// √2 + static constexpr double sqrt2 = 1.4142135623730950488; + + /// √3 + static constexpr double sqrt3 = 1.7320508075688772935; + + /// 1/√2 + static constexpr double _1_sqrt2 = 0.70710678118654752440; + + /// 1/√3 + static constexpr double _1_sqrt3 = 0.57735026918962576451; + //@} + + /** + *@name π and functions thereof + */ + //@{ + /// π + static constexpr double pi = 3.141592653589793238462643; + + /// 2π + static constexpr double _2pi = 6.283185307179586476925286; + + /// π/2 + static constexpr double pi_2 = 1.570796326794896619231322; + + /// π/4 + static constexpr double pi_4 = 0.7853981633974483096156608; + + /// 1/π + static constexpr double _1_pi = 0.3183098861837906715377675; + + /// 2/π + static constexpr double _2_pi = 0.6366197723675813430755350; + + /// 1/√π + static constexpr double _1_sqrtpi = 0.5641895835477562869480795; + + /// 2/√π + static constexpr double _2_sqrtpi = 1.1283791670955125738961590; + //@} + + /** + * @name e and functions thereof + */ + //@{ + /// e + static constexpr double e = 2.718281828459045235360287; + + /// ln(2) + static constexpr double ln2 = 0.6931471805599453094172321; + + /// ln(10) + static constexpr double ln10 = 2.3025850929940456840179915; + + /// log2(e) + static constexpr double log2e = 1.4426950408889634074; + + /// log10(e) + static constexpr double log10e = 0.4342944819032518276511289; + //@} + + /** + * @name gamma and functions thereof + */ + //@{ + /// gamma + static constexpr double gamma = 0.577215664901532860606512; + + /// ln(gamma) + static constexpr double lngamma = -0.549539312981644822337662; + + /// egamma + static constexpr double etogamma = 1.7810724179901979852; + //@} + + // End Mathematical constants + + + /* + * Begin Physical constants, and quantities + * + * References: + * "Explanatory Supplement to the Astronomical Almanac", + * + * "Handbook of Chemistry and Physics", 55th ed. + * Robert C. Weast (Ed), 1974. + * CRC Press Inc. + * ISBN 087819-54-1 + */ + + /** + * @name Fundamental physical constants (SI units) + */ + //@{ + /// velocity of light + static constexpr double c = 299792458; + + /// Gravitational constant + static constexpr double Gravity = 6.67259e-11; + + /// Planck's constant + static constexpr double Planck = 6.62607015e-34; + + /// gas constant + static constexpr double GasConst = 8.3144598; + + /// Avogardo's constant + static constexpr double Avogadro = 6.02214076e+23; + + /// electron charge + static constexpr double qe = 1.602176634e-19; + + /// proton mass + static constexpr double mp = 1.6726231e-27; + + /// proton mass / electron mass + static constexpr double mp_me = 1836.152701; + //@} + + /** + * @name Derived physical constants (SI units) + */ + //@{ + /// magnetic permeability of vacuum + static constexpr double mu0 = 4.0e-7 * C::pi; + + /// electric permittivity of vacuum + static constexpr double epsilon0 = 1.0 / ( C::mu0 * C::c * C::c ); + + /// Planck's constant divided by 2π + static constexpr double Planck_2pi = C::Planck / C::_2pi; + + /// atomic mass unit + static constexpr double u = 1.0e-3 / C::Avogadro; + + /// Boltzmann's constant + static constexpr double Boltzmann = C::GasConst / C::Avogadro; + + /// Faraday's constant + static constexpr double Faraday = C::Avogadro * C::qe; + + /// electron mass + static constexpr double me = C::mp / C::mp_me; + + /// classical electron radius + static constexpr double re = 2.8179e-15; + + /// Bohr radius + static constexpr double a0 = 5.2918e-11; + //@} + + /** + * @name Physical quantities (SI units) + */ + //@{ + /// solar radius + static constexpr double R0 = 6.9599e+08; + //@} + + // End Physical constants, and quantities + + + // Begin Physical units + + /** + * @name Numerical conversion factors + */ + //@{ + /// 1024 (Y) + static constexpr double yotta = 1.0e+24; + + /// 1021 (Z) + static constexpr double zetta = 1.0e+21; + + /// 1018 (E) + static constexpr double exa = 1.0e+18; + + /// 1015 (P) + static constexpr double peta = 1.0e+15; + + /// 1012 (T) + static constexpr double tera = 1.0e+12; + + /// 109 (G) + static constexpr double giga = 1.0e+09; + + /// 106 (M) + static constexpr double mega = 1.0e+06; + + /// 103 (k) + static constexpr double kilo = 1.0e+03; + + /// 102 (h) + static constexpr double hecto = 1.0e+02; + + /// 101 (D) + static constexpr double deka = 1.0e+01; + + /// 10-1 (d) + static constexpr double deci = 1.0e-01; + + /// 10-2 (c) + static constexpr double centi = 1.0e-02; + + /// 10-3 (m) + static constexpr double milli = 1.0e-03; + + /// 10-6 (u) + static constexpr double micro = 1.0e-06; + + /// 10-9 (n) + static constexpr double nano = 1.0e-09; + + /// 10-12 (p) + static constexpr double pico = 1.0e-12; + + /// 10-15 (f) + static constexpr double femto = 1.0e-15; + + /// 10-18 (a) + static constexpr double atto = 1.0e-18; + + /// 10-21 (z) + static constexpr double zepto = 1.0e-21; + + /// 10-24 (y) + static constexpr double yocto = 1.0e-24; + //@} + + /** + * @name Angular measure + */ + //@{ + /// radian + static constexpr double radian = 1.0; + + /// circle + static constexpr double circle = (2.0 * C::pi) * C::radian; + + /// circuit + static constexpr double circuit = C::circle; + + /// cycle + static constexpr double cycle = C::circle; + + /// revolution + static constexpr double rev = C::circle; + + /// revolution + static constexpr double revolution = C::circle; + + /// rotation + static constexpr double rotation = C::circle; + + /// degree + static constexpr double degree = (1.0 / 360.0) * C::circle; + + /// arcminute + static constexpr double arcmin = (1.0 / 60.0) * C::degree; + + /// arcsecond + static constexpr double arcsec = (1.0 / 60.0) * C::arcmin; + + /// grad + static constexpr double grad = (1.0 / 400.0) * C::circle; + //@} + + /** + * @name Solid angular measure + */ + //@{ + /// steradian + static constexpr double steradian = 1.0; + + /// sphere + static constexpr double sphere = (4.0 * C::pi) * C::steradian; + + /// square degree + static constexpr double square_degree = C::degree * C::degree; + + /// square arcminute + static constexpr double square_arcmin = C::arcmin * C::arcmin; + + /// square arcsecond + static constexpr double square_arcsec = C::arcsec * C::arcsec; + //@} + + // End Numerical conversion factors + + + // Begin Physical conversion factors + + /** + * @name Time interval [T] + */ + //@{ + /// second + static constexpr double second = 1.0; + + /// minute + static constexpr double minute = 60.0 * C::second; + + /// hour + static constexpr double hour = 60.0 * C::minute; + + /// day + static constexpr double day = 24.0 * C::hour; + + /// week + static constexpr double week = 7.0 * C::day; + + /// fortnight + static constexpr double fortnight = 2.0 * C::week; + //@} + + /** + * @name Frequency [1/T] + */ + //@{ + /// Hertz + static constexpr double Hertz = 1.0 / C::second; + //@} + + /** + * @name Length [L] + */ + //@{ + /// metre + static constexpr double metre = 1.0; + + /// metre (American spelling) + static constexpr double meter = C::metre; + + /// Fermi + static constexpr double Fermi = 1.0e-15 * C::metre; + + /// Angstrom + static constexpr double Angstrom = 1.0e-10 * C::metre; + + /// inch + static constexpr double inch = 2.54e-2 * C::metre; + + /// thou (inch/1000) + static constexpr double thou = 1.0e-3 * C::inch; + + /// hand + static constexpr double hand = 4.0 * C::inch; + + /// span + static constexpr double span = 9.0 * C::inch; + + /// foot + static constexpr double foot = 12.0 * C::inch; + + /// yard + static constexpr double yard = 3.0 * C::foot; + + /// fathom + static constexpr double fathom = 6.0 * C::foot; + + /// rod + static constexpr double rod = 16.5 * C::foot; + + /// perch + static constexpr double perch = C::rod; + + /// rope + static constexpr double rope = 20.0 * C::foot; + + /// chain + static constexpr double chain = 22.0 * C::yard; + + /// furlong + static constexpr double furlong = 220.0 * C::yard; + + /// English statute mile + static constexpr double mile = 5280.0 * C::foot; + + /// nautical mile + static constexpr double nautical_mile = 6080.0 * C::foot; + + /// point + static constexpr double point = (1.0 / 72.0) * C::inch; + + /// pica + static constexpr double pica = 12.0 * C::point; + + /// astronomical unit + static constexpr double astronomical_unit = 1.495978707e+11 * C::metre; + + /// light second + static constexpr double light_second = C::c * C::metre; + + /// light year + static constexpr double light_year = 9.46073047e+15 * C::metre; + + /// parsec + static constexpr double parsec = 3.26156378 * C::light_year; + //@} + + /** + * @name Area [L*L] + */ + //@{ + /// square metre + static constexpr double square_metre = C::metre * C::metre; + + /// square meter (American spelling) + static constexpr double square_meter = C::square_metre; + + /// are + static constexpr double are = 100.0 * C::square_metre; + + /// barn + static constexpr double barn = 1.0e-28 * C::square_metre; + + /// square inch + static constexpr double square_inch = C::inch * C::inch; + + /// square foot + static constexpr double square_foot = C::foot * C::foot; + + /// square yard + static constexpr double square_yard = C::yard * C::yard; + + /// square mile + static constexpr double square_mile = C::mile * C::mile; + + /// square perch + static constexpr double square_perch = C::perch * C::perch; + + /// rood + static constexpr double rood = 40.0 * C::square_perch; + + /// acre + static constexpr double acre = 4.0 * C::rood; + + /// square + static constexpr double square = 100.0 * C::square_foot; + //@} + + /** + * @name Volume [L*L*L] + */ + //@{ + /// cubic metre + static constexpr double cubic_metre = C::metre * C::square_metre; + + /// cubic meter (American spelling) + static constexpr double cubic_meter = C::cubic_metre; + + /// stere + static constexpr double stere = C::cubic_metre; + + /// litre + static constexpr double litre = 1.0e-3 * C::cubic_metre; + + /// liter (American spelling) + static constexpr double liter = C::litre; + + /// cubic inch + static constexpr double cubic_inch = C::inch * C::square_inch; + + /// cubic foot + static constexpr double cubic_foot = C::foot * C::square_foot; + + /// cubic yard + static constexpr double cubic_yard = C::yard * C::square_yard; + + /// cubic mile + static constexpr double cubic_mile = C::mile * C::square_mile; + + /// (Brit) gallon + static constexpr double gallon = 277.4193 * C::cubic_inch; + + /// (Brit) quart + static constexpr double quart = (1.0 / 4.0) * C::gallon; + + /// (Brit) pint + static constexpr double pint = (1.0 / 2.0) * C::quart; + + /// (Brit) gill + static constexpr double gill = (1.0 / 4.0) * C::pint; + + /// (Brit) fluid ounce + static constexpr double fluid_ounce = (1.0 / 5.0) * C::gill; + + /// (Brit) drachm + static constexpr double drachm = (1.0 / 8.0) * C::fluid_ounce; + + /// (Brit) scruple + static constexpr double scruple = (1.0 / 3.0) * C::drachm; + + /// (Brit) minim + static constexpr double minim = (1.0 / 20.0) * C::scruple; + + /// (US liq) gallon + static constexpr double USgallon = 231.0 * C::cubic_inch; + + /// (US liq) quart + static constexpr double USquart = (1.0 / 4.0) * C::USgallon; + + /// (US liq) pint + static constexpr double USpint = (1.0 / 2.0) * C::USquart; + + /// (US liq) gill + static constexpr double USgill = (1.0 / 4.0) * C::USpint; + + /// (US liq) fluid ounce + static constexpr double USfluid_ounce = (1.0 / 4.0) * C::USgill; + + /// (US liq) dram + static constexpr double USdram = (1.0 / 8.0) * C::USfluid_ounce; + + /// (US liq) minim + static constexpr double USminim = (1.0 / 60.0) * C::USdram; + //@} + + /** + * @name Speed [L/T] + */ + //@{ + /// nautical miles per hour + static constexpr double knot = C::nautical_mile / C::hour; + //@} + + /** + * @name Acceleration (speed / time) [L/(T*T)] + */ + //@{ + /// gravitational acceleration + static constexpr double g = 9.80665 * C::metre / C::second / C::second; + //@} + + /** + * @name Mass [M] + */ + //@{ + /// gram + static constexpr double gram = 0.001; + + /// metric ton + static constexpr double tonne = 1000.0 * C::kilo * C::gram; + + /// metric carat + static constexpr double carat = (1.0 / 5.0) * C::gram; + + /// pound (avoirdupois) + static constexpr double pound = 0.45359237 * C::kilo * C::gram; + + /// ounce (avoirdupois) + static constexpr double ounce = (1.0 / 16.0) * C::pound; + + /// stone + static constexpr double stone = 14.0 * C::pound; + + /// stone + static constexpr double quarter = 2.0 * C::stone; + + /// (long) hundredweight + static constexpr double hundredweight = 4.0 * C::quarter; + + /// (long) ton + static constexpr double ton = 20.0 * C::hundredweight; + + /// cental + static constexpr double cental = 100.0 * C::pound; + + /// short quarter (Brit) + static constexpr double shortquarter = 25.0 * C::pound; + + /// short hundredweight + static constexpr double shortcwt = 4.0 * C::shortquarter; + + /// short ton + static constexpr double shortton = 20.0 * C::shortcwt; + //@} + + /** + * @name Force (mass * acceleration) [M*L/(T*T)] + */ + //@{ + /// Newton + static constexpr double Newton = C::kilo * C::gram * C::metre / C::second / C::second; + + /// dyne + static constexpr double dyne = 1.0e-5 * C::Newton; + //@} + + /** + * @name Pressure (force / area) [M/(L*T*T)] + */ + //@{ + /// Pascal + static constexpr double Pascal = C::Newton / C::square_metre; + + /// atmosphere + static constexpr double atmosphere = 1.01325e+5 * C::Pascal; + + /// bar + static constexpr double bar = 1.0e+5 * C::Pascal; + + /// torr + static constexpr double torr = (1.0 / 760.0) * C::atmosphere; + + /// mm of Mercury + static constexpr double mmHg = (13.5951 * C::g) * C::Pascal; + //@} + + /** + * @name Energy (force * length) [M*L*L/(T*T)] + */ + //@{ + /// Joule + static constexpr double Joule = C::Newton * C::metre; + + /// kiloWatt * hour + static constexpr double kWh = 3.6e+6 * C::Joule; + + /// erg + static constexpr double erg = 1.0e-7 * C::Joule; + + /// calorie (thermochemical) + static constexpr double calorie = 4.184 * C::Joule; + + /// calorie (International Steam) + static constexpr double calorie_IT = 4.1868 * C::Joule; + + /// British thermal unit + static constexpr double Btu = 1.05435e+3 * C::Joule; + + /// electron volt + static constexpr double eV = C::qe * C::Joule; + //@} + + /** + * @name Temperature difference (energy) [M*L*L/(T*T)] + */ + //@{ + /// Kelvin + static constexpr double Kelvin = C::Boltzmann * C::Joule; + + /// Celsius + static constexpr double Celsius = C::Kelvin; + + /// Centigrade + static constexpr double Centigrade = C::Celsius; + + /// Fahrenheit + static constexpr double Fahrenheit = (5.0 / 9.0) * C::Kelvin; + + /// Rankine + static constexpr double Rankine = C::Fahrenheit; + //@} + + /** + * @name Temperature at 0 on each temperature scale + */ + //@{ + /// Absolute Zero (Kelvins) + static constexpr double Kelvin_0 = 0.0 * C::Kelvin; + + /// Celsius Zero + static constexpr double Celsius_0 = 273.15 * C::Kelvin; + + /// Centigrade Zero + static constexpr double Centigrade_0 = C::Celsius_0; + + /// Fahrenheit Zero + static constexpr double Fahrenheit_0 = 459.67 * C::Fahrenheit; + + /// Absolute Zero (Rankines) + static constexpr double Rankine_0 = 0.0 * C::Fahrenheit; + //@} + + /** + * @name Power (energy / time) [M*L*L/(T*T*T)] + */ + //@{ + /// Watt + static constexpr double Watt = C::Joule / C::second; + + /// horsepower + static constexpr double horsepower = 745.7 * C::Watt; + //@} + + /** + * @name Flux density (power / area / frequency) [M/(T*T)] + */ + //@{ + /// Jansky + static constexpr double Jansky = 1.0e-26 * C::Watt / C::square_metre / C::Hertz; + + /// flux units + static constexpr double fu = C::Jansky; + //@} + + /** + * @name Electric charge [Q] (Coulomb) + */ + //@{ + /// Coulomb + static constexpr double Coulomb = 1.0; + + /// abCoulomb (emu) + static constexpr double abCoulomb = 10.0 * C::Coulomb; + + /// statCoulomb (esu) + static constexpr double statCoulomb = (0.1 / C::c) * C::Coulomb; + //@} + + /** + * @name Electric current (charge / time) [Q/T] + */ + //@{ + /// Ampere + static constexpr double Ampere = C::Coulomb / C::second; + + /// abAmpere (emu) + static constexpr double abAmpere = 10.0 * C::Ampere; + + /// statAmpere (esu) + static constexpr double statAmpere = (0.1 / C::c) * C::Ampere; + //@} + + // Electric field strength (force / charge) [M*L/(T*T*Q)] + + /** + * @name Electric potential (energy / charge) [M*L*L/(T*T*Q)] + */ + //@{ + /// Volt + static constexpr double Volt = C::Joule / C::Coulomb; + + /// abVolt (emu) + static constexpr double abVolt = 1.0e-8 * C::Volt; + + /// statVolt (esu) + static constexpr double statVolt = (C::c * 1.0e-6) * C::Volt; + //@} + + /** + * @name Electric resistance (potential / current) [M*L*L/(T*Q*Q)]] + */ + //@{ + /// Ohm + static constexpr double Ohm = C::Volt / C::Ampere; + + /// abOhm (emu) + static constexpr double abOhm = 1.0e-9 * C::Ohm; + + /// starOhm (esu) + static constexpr double statOhm = (3.0e+3 * C::c) * C::Ohm; + //@} + + /** + * @name Electric conductance (current / potential) [T*Q*Q/(M*L*L)] + */ + //@{ + /// Siemens + static constexpr double Siemens = C::Ampere / C::Volt; + + /// mho + static constexpr double mho = C::Siemens; + //@} + + /** + * @name Electric capacitance (charge / potential) [T*T*Q*Q/(M*L*L)] + */ + //@{ + /// Farad + static constexpr double Farad = C::Coulomb / C::Volt; + + /// abFarad (emu) + static constexpr double abFarad = 1.0e+9 * C::Farad; + + /// statFarad (esu) + static constexpr double statFarad = 1.0 / (3.0e+3 * C::c) * C::Farad; + //@} + + /** + * @name Electric inductance (potential * time / current) [M*L*L/(Q*Q)] + */ + //@{ + /// Henry + static constexpr double Henry = C::Volt * C::second / C::Ampere; + + /// abHenry (emu) + static constexpr double abHenry = 1.0e-9 * C::Henry; + + /// statHenry (esu) + static constexpr double statHenry = (3.0e+3 * C::c) * C::Henry; + //@} + + /** + * @name Magnetic induction (force / charge / velocity) [M/(T*Q)] + */ + //@{ + /// Tesla + static constexpr double Tesla = C::Newton / C::Coulomb / (C::metre / C::second); + + /// Gauss (emu) + static constexpr double Gauss = 1.0e-4 * C::Tesla; + //@} + + /** + * @name Magnetic flux (magnetic induction * area) [M*L*L/(T*Q)] + */ + //@{ + /// Weber + static constexpr double Weber = C::Tesla / C::square_metre; + + /// Maxwell (emu) + static constexpr double Maxwell = 1.0e-8 * C::Weber; + + /// line (emu) + static constexpr double line = C::Maxwell; + //@} + + /** + * @name Magnetomotance = magnetomotive force (current) [Q/T] + */ + //@{ + /// Ampere-turn + static constexpr double Ampere_turn = C::Ampere; + + /// abAmpere-turn + static constexpr double abAmpere_turn = 10.0 * C::Ampere_turn; + + /// Gilbert (emu) + static constexpr double Gilbert = 10.0 / (4.0 * C::pi) * C::Ampere_turn; + + /// praGilbert (emu) + static constexpr double praGilbert = (4.0 * C::pi) * C::Ampere_turn; + //@} + + // Magnetic field intensity (current / length) [Q/(T*L)]: + //@{ + /// Oersted (emu) + static constexpr double Oersted = 1000.0 / (4.0 * C::pi) * C::Ampere / C::metre; + + /// praOersted (emu) + static constexpr double praOersted = (4.0 * C::pi) * C::Ampere / C::metre; + //@} + + /** + * @name Radioactivity (Bequerel) + */ + //@{ + /// Bequerel + static constexpr double Bequerel = 1.0; + //@} + + /** + * @name Luminous intensity [Iv] + */ + //@{ + /// candela + static constexpr double candela = 1.0; + //@} + + /** + * @name Amount of substance [N] + */ + //@{ + /// mole + static constexpr double mole = 1.0; + + /// number of molecules + static constexpr double molecule = (1.0 / C::Avogadro) * C::mole; + //@} + + // End Physical conversion factors + + // End Physical units + +} + +#endif /* MARC_AIPS_CONSTANTS_H */ diff --git a/lib/MaRC/CosPhaseImage.cpp b/lib/marc/CosPhaseImage.cpp similarity index 97% rename from lib/MaRC/CosPhaseImage.cpp rename to lib/marc/CosPhaseImage.cpp index 542b09a7..8404770d 100644 --- a/lib/MaRC/CosPhaseImage.cpp +++ b/lib/marc/CosPhaseImage.cpp @@ -25,6 +25,8 @@ #include "BodyData.h" #include "Constants.h" +#include + MaRC::CosPhaseImage::CosPhaseImage(std::shared_ptr body, double sub_observ_lat, @@ -61,5 +63,7 @@ MaRC::CosPhaseImage::read_data_i(double lat, lon, this->range_); + assert(data >= -1 && data <= 1); + return true; } diff --git a/lib/MaRC/CosPhaseImage.h b/lib/marc/CosPhaseImage.h similarity index 93% rename from lib/MaRC/CosPhaseImage.h rename to lib/marc/CosPhaseImage.h index e8f1db15..6030e27e 100644 --- a/lib/MaRC/CosPhaseImage.h +++ b/lib/marc/CosPhaseImage.h @@ -25,8 +25,8 @@ #ifndef MARC_COS_PHASE_IMAGE_H #define MARC_COS_PHASE_IMAGE_H -#include "MaRC/VirtualImage.h" -#include "MaRC/Export.h" +#include "marc/VirtualImage.h" +#include "marc/Export.h" #include @@ -36,7 +36,7 @@ namespace MaRC class BodyData; /** - * @class CosPhaseImage + * @class CosPhaseImage CosPhaseImage.h * * @brief Cosine of phase angle (i.e. cos(φ)) virtual * image. @@ -77,6 +77,9 @@ namespace MaRC double scale, double offset); + /// Destructor. + virtual ~CosPhaseImage() = default; + private: /// Compute cosine of phase angle, @c cos(φ). @@ -85,7 +88,7 @@ namespace MaRC */ virtual bool read_data_i(double lat, double lon, - double & data) const; + double & data) const override; private: diff --git a/lib/MaRC/DefaultConfiguration.h b/lib/marc/DefaultConfiguration.h similarity index 96% rename from lib/MaRC/DefaultConfiguration.h rename to lib/marc/DefaultConfiguration.h index 9ae13b65..332b96a1 100644 --- a/lib/MaRC/DefaultConfiguration.h +++ b/lib/marc/DefaultConfiguration.h @@ -32,9 +32,9 @@ namespace MaRC /** * @namespace default_configuration * - * @brief Default MaRC configuration constants. + * @brief Default %MaRC configuration constants. * - * These constants are used throughout MaRC when a corresponding + * These constants are used throughout %MaRC when a corresponding * user-supplied value is not available. */ namespace default_configuration diff --git a/lib/MaRC/Export.h b/lib/marc/Export.h similarity index 89% rename from lib/MaRC/Export.h rename to lib/marc/Export.h index 62c84818..c6ac2af5 100644 --- a/lib/MaRC/Export.h +++ b/lib/marc/Export.h @@ -34,9 +34,9 @@ # define MARC_DLL_LOCAL #else # if __GNUC__ >= 4 -# define MARC_DLL_IMPORT __attribute__((visibility ("default"))) -# define MARC_DLL_EXPORT __attribute__((visibility ("default"))) -# define MARC_DLL_LOCAL __attribute__((visibility ("hidden"))) +# define MARC_DLL_IMPORT [[gnu::visibility("default")]] +# define MARC_DLL_EXPORT [[gnu::visibility("default")]] +# define MARC_DLL_LOCAL [[gnu::visibility("hidden")]] # else # define MARC_DLL_IMPORT # define MARC_DLL_EXPORT diff --git a/lib/MaRC/GLLGeometricCorrection.cpp b/lib/marc/GLLGeometricCorrection.cpp similarity index 95% rename from lib/MaRC/GLLGeometricCorrection.cpp rename to lib/marc/GLLGeometricCorrection.cpp index fcba1da1..aae84681 100644 --- a/lib/MaRC/GLLGeometricCorrection.cpp +++ b/lib/marc/GLLGeometricCorrection.cpp @@ -20,7 +20,7 @@ * * @author Ossama Othman */ -#include +#include #include @@ -34,13 +34,13 @@ namespace MaRC */ namespace GLL { - // The distortion constant must be a positive number. + /// The distortion constant must be a positive number. static constexpr double DISTORTION = 0.00000000658; - // Default optical axis line. + /// Default optical axis line. static constexpr double OA_LINE = 400; - // Default optical axis sample. + /// Default optical axis sample. static constexpr double OA_SAMPLE = 400; } } diff --git a/lib/MaRC/GLLGeometricCorrection.h b/lib/marc/GLLGeometricCorrection.h similarity index 86% rename from lib/MaRC/GLLGeometricCorrection.h rename to lib/marc/GLLGeometricCorrection.h index 2deec22d..f5ae42fb 100644 --- a/lib/MaRC/GLLGeometricCorrection.h +++ b/lib/marc/GLLGeometricCorrection.h @@ -29,8 +29,8 @@ #ifndef MARC_GLL_GEOMETRIC_CORRECTION_H #define MARC_GLL_GEOMETRIC_CORRECTION_H -#include -#include +#include +#include #include @@ -44,7 +44,7 @@ namespace MaRC { /** - * @class GLLGeometricCorrection + * @class GLLGeometricCorrection GLLGeometricCorrection.h * * @brief Galileo Spacecraft lens aberration correction strategy. * @@ -70,8 +70,10 @@ namespace MaRC * base class. */ //@{ - void image_to_object(double & line, double & sample) const; - void object_to_image(double & line, double & sample) const; + void image_to_object(double & line, + double & sample) const override; + void object_to_image(double & line, + double & sample) const override; //@} /// Return current summation mode diff --git a/lib/MaRC/GeometricCorrection.h b/lib/marc/GeometricCorrection.h similarity index 96% rename from lib/MaRC/GeometricCorrection.h rename to lib/marc/GeometricCorrection.h index 2984a1bc..24a8f105 100644 --- a/lib/MaRC/GeometricCorrection.h +++ b/lib/marc/GeometricCorrection.h @@ -25,14 +25,14 @@ #ifndef MARC_GEOMETRIC_CORRECTION_H #define MARC_GEOMETRIC_CORRECTION_H -#include +#include namespace MaRC { /** - * @class GeometricCorrection + * @class GeometricCorrection GeometricCorrection.h * * @brief Abstract base class for all geometric correction * strategies. diff --git a/lib/MaRC/Geometry.cpp b/lib/marc/Geometry.cpp similarity index 100% rename from lib/MaRC/Geometry.cpp rename to lib/marc/Geometry.cpp diff --git a/lib/MaRC/Geometry.h b/lib/marc/Geometry.h similarity index 99% rename from lib/MaRC/Geometry.h rename to lib/marc/Geometry.h index b872a8ec..0a27f7d3 100644 --- a/lib/MaRC/Geometry.h +++ b/lib/marc/Geometry.h @@ -27,8 +27,8 @@ #ifndef MARC_GEOMETRY_H #define MARC_GEOMETRY_H -#include -#include +#include +#include #include diff --git a/lib/MaRC/InterpolationStrategy.h b/lib/marc/InterpolationStrategy.h similarity index 95% rename from lib/MaRC/InterpolationStrategy.h rename to lib/marc/InterpolationStrategy.h index ee540c70..c73d6096 100644 --- a/lib/MaRC/InterpolationStrategy.h +++ b/lib/marc/InterpolationStrategy.h @@ -25,14 +25,14 @@ #ifndef MARC_INTERPOLATION_STRATEGY_H #define MARC_INTERPOLATION_STRATEGY_H -#include +#include namespace MaRC { /** - * @class InterpolationStrategy + * @class InterpolationStrategy InterpolationStrategy.h * * @brief Abstract base class for all interpolation strategies. * diff --git a/lib/MaRC/LatitudeImage.cpp b/lib/marc/LatitudeImage.cpp similarity index 100% rename from lib/MaRC/LatitudeImage.cpp rename to lib/marc/LatitudeImage.cpp diff --git a/lib/MaRC/LatitudeImage.h b/lib/marc/LatitudeImage.h similarity index 90% rename from lib/MaRC/LatitudeImage.h rename to lib/marc/LatitudeImage.h index 70e7804f..e2725efe 100644 --- a/lib/MaRC/LatitudeImage.h +++ b/lib/marc/LatitudeImage.h @@ -25,8 +25,8 @@ #ifndef MARC_LATITUDE_IMAGE_H #define MARC_LATITUDE_IMAGE_H -#include "MaRC/VirtualImage.h" -#include "MaRC/Export.h" +#include "marc/VirtualImage.h" +#include "marc/Export.h" #include @@ -36,7 +36,7 @@ namespace MaRC class BodyData; /** - * @class LatitudeImage + * @class LatitudeImage LatitudeImage.h * * @brief Latitude virtual image. * @@ -78,9 +78,9 @@ namespace MaRC * @note "deg" is used is instead of "degree" per FITS * standard recommendation for the BUNIT keyword. * - * @se https://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html + * @see https://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html */ - virtual char const * unit() const { return "deg"; } + virtual char const * unit() const override { return "deg"; } private: @@ -90,7 +90,7 @@ namespace MaRC */ virtual bool read_data_i(double lat, double lon, - double & data) const; + double & data) const override; private: diff --git a/lib/marc/Log.cpp b/lib/marc/Log.cpp new file mode 100644 index 00000000..c4fb7f98 --- /dev/null +++ b/lib/marc/Log.cpp @@ -0,0 +1,75 @@ +// -*- C++ -*- +/** + * @file Log.cpp + * + * Copyright (C) 2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +/** + * @todo Ideally we shouldn't have to include this header since the + * underlying %MaRC logger shouldn't be exposed to the user. + */ +#include "Export.h" // For MARC_API +#include "Log.h" + + +namespace +{ + inline void marc_log(char const * level, + char const * format, + fmt::format_args args) + { + fmt::print("[" PACKAGE "][{}] ", level); + fmt::vprint(format, args); + fmt::print("\n"); + } +} + +// -------------------------------------------------------------- + +MARC_API void +MaRC::details::debug(char const * format, fmt::format_args args) +{ + marc_log("debug", format, args); +} + +MARC_API void +MaRC::details::info(char const * format, fmt::format_args args) +{ + marc_log("info", format, args); +} + +MARC_API void +MaRC::details::warn(char const * format, fmt::format_args args) +{ + marc_log("warn", format, args); +} + +MARC_API void +MaRC::details::error(char const * format, fmt::format_args args) +{ + marc_log("error", format, args); +} + +MARC_API void +MaRC::details::critical(char const * format, fmt::format_args args) +{ + marc_log("critical", format, args); +} diff --git a/lib/marc/Log.h b/lib/marc/Log.h new file mode 100644 index 00000000..f421a994 --- /dev/null +++ b/lib/marc/Log.h @@ -0,0 +1,182 @@ +// -*- C++ -*- +/** + * @file Log.h + * + * @brief %MaRC logging interface. + * + * Copyright (C) 2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + * + * @bug We really shouldn't be exposing to the user + * since it contains preprocessor symbols that pollute the global + * namespace. + */ + +#ifndef MARC_LOG_H +#define MARC_LOG_H + +#include "marc/config.h" // For NDEBUG + +// See https://github.com/fmtlib/fmt/issues/947 +#ifdef __GNUG__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +/// Avoid having to link the fmt library. +#define FMT_HEADER_ONLY +#include +#ifdef __GNUG__ +# pragma GCC diagnostic pop +#endif + +/** + * @def MARC_DEBUG_ARGS(x) + * + * @brief Mark MaRC::debug() parameters as unused as needed. + * + * The MaRC::debug() function parameters are only used when debugging + * is enabled (@c NDEBUG preprocessor symbol is undefined), or when + * Doxygen documentation is being generated. Mark as unused them by the + * standard C++ method of doing so when debugging is disabled, i.e. by + * preventing the parameter name @a x from expanding in that case. + * + * @param x MaRC::debug() parameter name. + * + * @note @c DXGEN is defined when building %MaRC's Doxygen based + * documentation. We want the MaRC::debug() arguments to be + * expanded in that case so that Doxygen generates documentation + * for them. + * + * @note This is an internal macro that is not meant for use outside + * of %MaRC. + */ +#if defined(NDEBUG) && !defined(DXGEN) +# define MARC_DEBUG_ARGS(x) +#else +# define MARC_DEBUG_ARGS(x) x +#endif // NDEBUG + + +namespace MaRC +{ + namespace details + { + /** + * @name Internal logging functions. + */ + //@{ + void debug(char const * format, fmt::format_args args); + void info(char const * format, fmt::format_args args); + void warn(char const * format, fmt::format_args args); + void error(char const * format, fmt::format_args args); + void critical(char const * format, fmt::format_args args); + //@} + } + + /** + * @brief Log debugging messages. + * + * @param[in] format Format of the text being logged, where the + * syntax is defined by the @c fmt library. + * @param[in] args Argument values corresponding to placeholder + * in the @a format string. + * + * @see http://fmtlib.net/latest/index.html + */ + template + void + debug(char const * MARC_DEBUG_ARGS(format), + Args const & ... MARC_DEBUG_ARGS(args)) + { +#ifndef NDEBUG + details::debug(format, fmt::make_format_args(args...)); +#endif // NDEBUG + } + + /** + * @brief Log information messages. + * + * @param[in] format Format of the text being logged, where the + * syntax is defined by the @c fmt library. + * @param[in] args Argument values corresponding to placeholder + * in the @a format string. + * + * @see http://fmtlib.net/latest/index.html + */ + template + void + info(char const * format, Args const & ... args) + { + details::info(format, fmt::make_format_args(args...)); + } + + /** + * @brief Log warning messages. + * + * @param[in] format Format of the text being logged, where the + * syntax is defined by the @c fmt library. + * @param[in] args Argument values corresponding to placeholder + * in the @a format string. + * + * @see http://fmtlib.net/latest/index.html + */ + template + void + warn(char const * format, Args const & ... args) + { + details::warn(format, fmt::make_format_args(args...)); + } + + /** + * @brief Log error messages. + * + * @param[in] format Format of the text being logged, where the + * syntax is defined by the @c fmt library. + * @param[in] args Argument values corresponding to placeholder + * in the @a format string. + * + * @see http://fmtlib.net/latest/index.html + */ + template + void + error(char const * format, Args const & ... args) + { + details::error(format, fmt::make_format_args(args...)); + } + + /** + * @brief Log critical messages. + * + * @param[in] format Format of the text being logged, where the + * syntax is defined by the @c fmt library. + * @param[in] args Argument values corresponding to placeholder + * in the @a format string. + * + * @see http://fmtlib.net/latest/index.html + */ + template + void + critical(char const * format, Args const & ... args) + { + details::critical(format, fmt::make_format_args(args...)); + } +} + + +#endif // MARC_LOG_H diff --git a/lib/MaRC/LongitudeImage.cpp b/lib/marc/LongitudeImage.cpp similarity index 99% rename from lib/MaRC/LongitudeImage.cpp rename to lib/marc/LongitudeImage.cpp index de536bc9..98231c31 100644 --- a/lib/MaRC/LongitudeImage.cpp +++ b/lib/marc/LongitudeImage.cpp @@ -25,6 +25,8 @@ #include "Constants.h" #include "DefaultConfiguration.h" +#include + MaRC::LongitudeImage::LongitudeImage(double scale, double offset) : VirtualImage(scale, offset) diff --git a/lib/MaRC/LongitudeImage.h b/lib/marc/LongitudeImage.h similarity index 85% rename from lib/MaRC/LongitudeImage.h rename to lib/marc/LongitudeImage.h index 327e0d69..55fb53ab 100644 --- a/lib/MaRC/LongitudeImage.h +++ b/lib/marc/LongitudeImage.h @@ -25,15 +25,15 @@ #ifndef MARC_LONGITUDE_IMAGE_H #define MARC_LONGITUDE_IMAGE_H -#include "MaRC/VirtualImage.h" -#include "MaRC/Export.h" +#include "marc/VirtualImage.h" +#include "marc/Export.h" namespace MaRC { /** - * @class LongitudeImage + * @class LongitudeImage LongitudeImage.h * * @brief Longitude virtual image. * @@ -55,6 +55,9 @@ namespace MaRC */ LongitudeImage(double scale, double offset); + /// Destructor. + virtual ~LongitudeImage() = default; + /** * @brief Angle unit of longitudes generated by this class. * @@ -65,9 +68,9 @@ namespace MaRC * @note "deg" is used is instead of "degree" per FITS * standard recommendation for the BUNIT keyword. * - * @se https://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html + * @see https://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html */ - virtual char const * unit() const { return "deg"; } + virtual char const * unit() const override { return "deg"; } private: @@ -77,7 +80,7 @@ namespace MaRC */ virtual bool read_data_i(double lat, double lon, - double & data) const; + double & data) const override; }; diff --git a/lib/MaRC/Makefile.am b/lib/marc/Makefile.am similarity index 92% rename from lib/MaRC/Makefile.am rename to lib/marc/Makefile.am index be299445..b953735d 100644 --- a/lib/MaRC/Makefile.am +++ b/lib/marc/Makefile.am @@ -28,6 +28,7 @@ endif AM_CPPFLAGS = \ -I$(top_builddir)/lib \ -I$(top_srcdir)/lib \ + $(FMTLIB_CPPFLAGS) \ $(CODE_COVERAGE_CPPFLAGS) \ $(DLL_CPPFLAGS) @@ -35,6 +36,7 @@ lib_LTLIBRARIES = libMaRC.la libMaRC_la_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) libMaRC_la_LIBADD = $(CODE_COVERAGE_LIBS) +libMaRC_la_LDFLAGS = $(MARC_UNUSED_ARGUMENT_LDFLAGS) libMaRC_la_SOURCES = \ Log.cpp \ @@ -42,7 +44,6 @@ libMaRC_la_SOURCES = \ \ Geometry.cpp \ \ - BodyData.cpp \ OblateSpheroid.cpp \ \ ViewingGeometry.cpp \ @@ -72,11 +73,9 @@ libMaRC_la_SOURCES = \ PolarStereographic.cpp \ SimpleCylindrical.cpp \ \ - root_find.cpp \ - \ - Version.cpp + root_find.cpp -pkginclude_HEADERS = \ +nobase_pkginclude_HEADERS = \ Log.h \ Observer.h \ Notifier.h \ @@ -124,17 +123,19 @@ pkginclude_HEADERS = \ PolarStereographic.h \ SimpleCylindrical.h \ Validate.h \ + optional.h \ plot_info.h \ root_find.h \ + scale_and_offset.h \ utility.h \ \ Constants.h \ \ - Version.h \ + Export.h \ \ - Export.h + details/scale_and_offset.h \ + details/vector.h # noinst_HEADERS = clean-local: code-coverage-clean -dist-clean-local: code-coverage-dist-clean diff --git a/lib/MaRC/MapFactory.cpp b/lib/marc/MapFactory.cpp similarity index 68% rename from lib/MaRC/MapFactory.cpp rename to lib/marc/MapFactory.cpp index 79ef4bcd..b0927f23 100644 --- a/lib/MaRC/MapFactory.cpp +++ b/lib/marc/MapFactory.cpp @@ -30,6 +30,18 @@ MaRC::MapFactory::make_grid(std::size_t samples, double lat_interval, double lon_interval) { + /** + * @todo Verify that @a lat_interval falls within the maximum + * latitude range in degrees, i.e. the half-open interval + * [0, 180) (always positive!), and similarly for the + * @c lon_interval and the longitude range [0, 360). The + * values should be large enough to ensure that data is + * always "behind" the grid, otherwise. %MaRC and the %MaRC + * library should not allow the invalid lat/lon grid + * intervals to be set to begin with. Such inputs should be + * validated beyond the existing negative value checks. + */ + grid_type grid(samples * lines, grid_type::value_type()); this->plot_grid(samples, diff --git a/lib/MaRC/MapFactory.h b/lib/marc/MapFactory.h similarity index 71% rename from lib/MaRC/MapFactory.h rename to lib/marc/MapFactory.h index 2b98096c..69c1855f 100644 --- a/lib/MaRC/MapFactory.h +++ b/lib/marc/MapFactory.h @@ -25,7 +25,7 @@ #ifndef MARC_MAP_FACTORY_H #define MARC_MAP_FACTORY_H -#include +#include #include #include @@ -39,30 +39,30 @@ namespace MaRC class plot_info; /** - * @class MapFactory + * @class MapFactory MapFactory.h * * @brief Map Abstract Factory * - * Abstract Factory class for map projections supported by MaRC. + * Abstract Factory class for map projections supported by %MaRC. */ class MARC_API MapFactory { public: - /// @typedef Type returned from @c make_map() method. + /// Type returned from @c make_map() method. template using map_type = std::vector; - /// @typedef Type returned from @c make_grid() method. - using grid_type = std::vector; + /// Type returned from @c make_grid() method. + using grid_type = std::vector; /** - * Map plot functor type. + * @brief Map plot functor type. * * Concrete map factories will call a function of this type in * their @c plot_map() implementation. * - * @see @c plot() for parameter details. + * @see @c plot() * */ using plot_type = @@ -83,17 +83,22 @@ namespace MaRC /// Return the name of the map projection. virtual char const * projection_name() const = 0; - /// Create the desired map projection. /** + * @brief Create the map projection. + * * This method takes care of allocating and initializing the * underlying map array, and delegates actual mapping to the * subclass implementation of @c plot_map(). * - * @param[in] info Map plotting information, such as the - * source image, min/max allowed data - * values, etc. - * @param[in] samples Number of samples in map. - * @param[in] lines Number of lines in map. + * @tparam T Map element data type. + * @param[in,out] info Map plotting information, such as + * the source image, min/max allowed + * data values, etc. Some fields, such + * as the minimum and maximum, may be + * updated to reflect the actual values + * used when creating the map. + * @param[in] samples Number of samples in map. + * @param[in] lines Number of lines in map. * * @return The generated map image. * @@ -101,13 +106,14 @@ namespace MaRC * the returned map. */ template - map_type make_map(plot_info const & info, + map_type make_map(plot_info & info, std::size_t samples, std::size_t lines); - /// Create the latitude/longitude grid for the desired map - /// projection. /** + * @brief Create the latitude/longitude grid for the map + * projection. + * * This method takes care of allocating and initializing the * underlying grid array, and delegates actual grid generation * to the subclass implementation of @c plot_grid(). @@ -136,7 +142,7 @@ namespace MaRC private: /** - * Create the desired map projection. + * @brief Create the desired map projection. * * @param[in] samples Number of samples in map. * @param[in] lines Number of lines in map. @@ -147,42 +153,36 @@ namespace MaRC std::size_t lines, plot_type plot) const = 0; - /// Plot the data on the map. /** + * @brief Plot the data on the map. + * * Plot the data at given latitude and longitude on the map. * Map implementation end up calling this function indirectly * through a function object that shields the caller from most * of these parameters. * - * @see @c plot_type type alias + * @see @c plot_type * @see @c plot_map() * - * @param[in] source SourceImage object - * containing the data to be - * mapped. - * @param[in] minimum Minimum allowed value on - * map, i.e. all data greater - * than or equal to - * @a minimum. - * @param[in] maximum Maximum allowed value on - * map, i.e. all data less - * than or equal to - * @a maximum. - * @param[in] lat Planetocentric latitude. - * @param[in] lon Planetocentric longitude. - * @param[in] percent_complete Percent of map completed. - * @param[in] offset Map offset corresponding to - * the location in the - * underlying map array where - * the data will be plotted. - * @param[in,out] map Map container where data - * will be plotted. + * @tparam T Map element data type. + * @param[in] info Map plotting information. + * @param[in] lat Planetocentric latitude. + * @param[in] lon Planetocentric longitude. + * @param[in] offset Map offset corresponding to the + * location in the underlying map array + * where the data will be plotted. + * @param[in,out] map Map container where data will be + * plotted. * * @todo Currently subclasses must call this method in their * @c plot_map() implementation. That seems like a * rather roundabout way of mapping the data. Ideally * @c make_map() should handle the map array iteration * as well as calling this @c plot() method. + * + * @todo This method has too many parameters. Move most, + * if not all, of the parameters to a structure that + * will be passed in as a single parameter instead. */ template void plot(plot_info const & info, @@ -191,9 +191,9 @@ namespace MaRC std::size_t offset, map_type & map); - /// Create the latitude/longitude grid for the desired map - /// projection. /** + * @brief Plot latitude/longitude grid for the map. + * * @param[in] samples Number of samples in grid. * @param[in] lines Number of lines in grid. * @param[in] lat_interval Number of degrees between each @@ -217,6 +217,6 @@ namespace MaRC } -#include "MaRC/MapFactory_t.cpp" +#include "marc/MapFactory_t.cpp" #endif // MARC_MAP_FACTORY_H diff --git a/lib/MaRC/MapFactory_t.cpp b/lib/marc/MapFactory_t.cpp similarity index 64% rename from lib/MaRC/MapFactory_t.cpp rename to lib/marc/MapFactory_t.cpp index 371205f5..4b57efa4 100644 --- a/lib/MaRC/MapFactory_t.cpp +++ b/lib/marc/MapFactory_t.cpp @@ -21,27 +21,46 @@ * @author Ossama Othman */ -#include "MaRC/MapFactory.h" -#include "MaRC/Map_traits.h" -#include "MaRC/SourceImage.h" -#include "MaRC/plot_info.h" +#ifndef MARC_MAP_FACTORY_T_CPP +#define MARC_MAP_FACTORY_T_CPP + +#include "marc/MapFactory.h" +#include "marc/Map_traits.h" +#include "marc/SourceImage.h" +#include "marc/plot_info.h" + +#include +#include +#include template MaRC::MapFactory::map_type -MaRC::MapFactory::make_map(plot_info const & info, +MaRC::MapFactory::make_map(plot_info & info, std::size_t samples, std::size_t lines) { - map_type map(samples * lines, Map_traits::empty_value()); + T blank = Map_traits::empty_value(); + + if (std::is_integral::value && info.blank()) { + if (info.blank() < std::numeric_limits::lowest() + || info.blank() > std::numeric_limits::max()) { + throw std::invalid_argument("Blank map value does not fit " + "within map data type."); + } + + blank = static_cast(*info.blank()); + } + + T const actual_min = Map_traits::minimum(info.minimum()); + T const actual_max = Map_traits::maximum(info.maximum()); + info.minimum(actual_min); + info.maximum(actual_max); + + map_type map(samples * lines, blank); using namespace std::placeholders; - /** - * @todo This is an absurd amount of parameters. Move most, if - * not all, of the parameters to a structure that will be - * passed in as a single parameter instead. - */ auto plot = std::bind(&MapFactory::plot, this, std::cref(info), @@ -63,7 +82,6 @@ void MaRC::MapFactory::plot(plot_info const & info, double lat, double lon, - // unsigned char percent_complete, std::size_t offset, map_type & map) { @@ -72,20 +90,15 @@ MaRC::MapFactory::plot(plot_info const & info, bool const found_data = (info.source().read_data(lat, lon, datum) - && datum >= Map_traits::minimum(info.minimum()) - && datum <= Map_traits::maximum(info.maximum())); - - if (found_data) { - T & data = -#ifdef NDEBUG - map[offset]; // No bounds check. -#else - map.at(offset); // Perform bounds check. -#endif - - data = static_cast(datum); - } + && datum >= info.minimum() + && datum <= info.maximum()); + + if (found_data) + map[offset] = static_cast(datum); // Inform "observers" of mapping progress. info.notifier().notify_plotted(map.size()); } + + +#endif // MARC_MAP_FACTORY_T_CPP diff --git a/lib/MaRC/Map_traits.h b/lib/marc/Map_traits.h similarity index 62% rename from lib/MaRC/Map_traits.h rename to lib/marc/Map_traits.h index 50784cdc..f305cdbc 100644 --- a/lib/MaRC/Map_traits.h +++ b/lib/marc/Map_traits.h @@ -2,7 +2,7 @@ /** * @file Map_traits.h * - * Copyright (C) 2004, 2017 Ossama Othman + * Copyright (C) 2004, 2017-2018 Ossama Othman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,32 +26,39 @@ #define MARC_MAP_TRAITS_H #include +#include /** * @namespace MaRC * - * @brief Code specific to the MaRC library and program. + * @brief Code specific to the %MaRC library and program. */ namespace MaRC { /** - * @struct Map_traits + * @struct Map_traits Map_traits.h * - * @brief @c Map traits template structure. + * @brief @c Traits specific to a map data type. * - * The @c Map template class delegates some operations to this - * template traits structure. + * These traits are used making a map projection to obtain map + * data type-specific characteristics, such as the default empty + * (blank) value, and map data "clipping" values. + * + * @tparam T Map data type. + * + * @see MapFactory */ template struct Map_traits { - /// Value used to initialize an empty map. /** + * @brief Value used to initialize an empty map. + * * The initial/empty map data value for integer typed maps * will be zero, but the value for floating point typed maps - * in MaRC is the Not-a-Number constant, not zero. This + * in %MaRC is the Not-a-Number constant, not zero. This * allows for easy disambiguation between actual data and * areas of the map that contain no data. */ @@ -60,14 +67,15 @@ namespace MaRC return std::numeric_limits::quiet_NaN(); } - /// Make sure given minimum value falls within map data type - /// range. /** + * @brief Make sure given minimum value falls within map data + * type range. + * * The idea behind this trait is to prevent data that is * actually outside the valid data range of the map data type * from being mapped. In particular, the minimum value is * "clipped" if necessary. - * @par + * * If an invalid minimum is used, data may be cast to a value * that is significantly different than its original value. * For example, setting the minimum to -65000 for a signed @@ -77,78 +85,61 @@ namespace MaRC * integer set to -65000 results in a short integer value of * 536). * - * @param[in] min User configured minimum. + * @param[in] m User configured minimum. * * @return Minimum value that is greater than or equal to the * minimum valid value for the given map data type. */ - static T minimum(double min) + static T minimum(double m) { - static constexpr T const absolute_min = - std::numeric_limits::lowest(); + constexpr double type_min = std::numeric_limits::lowest(); - return (min < absolute_min - ? absolute_min : static_cast(min)); + // Return the larger of the two minimums. + return std::max(m, type_min); } - /// Make sure given maximum value falls within map data type - /// range. /** + * @brief Make sure given maximum value falls within map data + * type range. + * * The idea behind this trait is to prevent data that is actually * outside the valid data range of the map data type from being * mapped. In particular, the maximum value is "clipped" if * necessary. * - * @see The discussion for the @c minimum trait for additional - * details. + * @see @c minimum() * - * @param max User configured maximum. + * @param[in] m User configured maximum. * * @return Maximum value that is less than or equal to the * maximum valid value for the given map data type. */ - static T maximum(double max) + static T maximum(double m) { - static constexpr T const absolute_max = - std::numeric_limits::max(); + constexpr double type_max = std::numeric_limits::max(); - return (max > absolute_max - ? absolute_max : static_cast(max)); - } - }; - - // Map_traits specializations. - template <> - struct Map_traits - { - static constexpr float empty_value() - { - return std::numeric_limits::quiet_NaN(); - } - - static float minimum(double min) - { - /** - * @todo Why do we need to add one here? - */ - static constexpr float const absolute_min = - std::numeric_limits::lowest() + 1; - - return (min < absolute_min ? absolute_min : min); - } - - static float maximum(double max) - { - static constexpr float const absolute_max = - std::numeric_limits::max(); - - return (max > absolute_max ? absolute_max : max); + // Return the smaller of the two maximums. + return std::min(m, type_max); } }; + /** + * @struct Map_traits Map_traits.h + * + * @brief @c Map_traits specialization for maps with a @c double + * data type. + * + * @see Map_traits + */ template <> struct Map_traits { + /** + * @name Specialized Members + * + * Members specialized for type @c double. + */ + //@{ static constexpr double empty_value() { return std::numeric_limits::quiet_NaN(); @@ -167,6 +158,7 @@ namespace MaRC // same. return max; } + //@} }; } diff --git a/lib/MaRC/Mathematics.h b/lib/marc/Mathematics.h similarity index 86% rename from lib/MaRC/Mathematics.h rename to lib/marc/Mathematics.h index 555ac245..114dce05 100644 --- a/lib/MaRC/Mathematics.h +++ b/lib/marc/Mathematics.h @@ -29,13 +29,6 @@ #ifndef MARC_MATHEMATICS_H #define MARC_MATHEMATICS_H -/** - * @bug We really shouldn't be exposing to the user - * since it contains preprocessor symbols that pollute the global - * namespace. - */ -#include "MaRC/config.h" // For MARC_HAS_3_PARAM_STD_HYPOT - #include #include #include @@ -44,7 +37,7 @@ namespace MaRC { -#ifndef MARC_HAS_3_PARAM_STD_HYPOT +#if __cplusplus < 201703L /** * @brief Distance of (x,y,z) from the origin. * @@ -66,7 +59,7 @@ namespace MaRC * * @deprecated This implementation of the three-parameter * @c std::hypot() will be dropped once we start - * using C++17 features in MaRC. + * using C++17 features in %MaRC. */ template auto hypot(T x, T y, T z) @@ -86,12 +79,12 @@ namespace MaRC */ return std::hypot(std::hypot(x, y), z); } -#endif // !MARC_HAS_3_PARAM_STD_HYPOT +#endif // __cplusplus < 201703L using std::hypot; /** - * @brief Compare two floating numbers for equality. + * @brief Compare two floating point numbers for equality. * * Floating point values cannot be reliably compared for equaility * using the typical @c operator==(). Determine if two floating @@ -117,7 +110,7 @@ namespace MaRC * @return @c true @a x and @a y are essentially equal. @c false * otherwise. * - * @see The @c std::numeric_limits<>::epsilon() discussion on + * @see The @c std::numeric_limits::epsilon() discussion on * cppreference.com for the original implementation of this * function: * http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon @@ -128,7 +121,7 @@ namespace MaRC * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */ template - typename std::enable_if_t::is_integer, bool> + typename std::enable_if_t::value, bool> almost_equal(T x, T y, int ulp) { /* @@ -144,7 +137,7 @@ namespace MaRC } /** - * @brief Check if floating number is almost zero. + * @brief Check if floating point number is almost zero. * * Determine if a floating point number is essentially zero by * comparing it against a small multiple of @c epsilon @@ -172,7 +165,7 @@ namespace MaRC * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */ template - typename std::enable_if_t::is_integer, bool> + typename std::enable_if_t::value, bool> almost_zero(T x, int n) { /** @@ -198,6 +191,24 @@ namespace MaRC return (x > T(0)) - (x < T(0)); } + /** + * @brief Return sign of a real number. + * + * This function differs from the @c signum() function in that it + * interprets the value zero (@a x == 0) as having a positive + * sign, i.e. @c 1, instead of @c 0. + * + * @retval -1 if @a x < 0 + * @retval 1 if @a x >= 0 + */ + template + int + sgn(T x) + { + // Iverson bracket notation of the sgn function. + return (x >= T(0)) - (x < T(0)); + } + /** * @brief Solve the quadratic formula in a numerically stable * manner. @@ -234,7 +245,15 @@ namespace MaRC if (discriminant < 0) return false; // Roots are not real. - double const q = -(b + signum(b) * std::sqrt(discriminant)) / 2; + /** + * @note We do not use signum() here since @c signum(b) when + * @c b is zero would return @c 0, resulting in + * incorrect root results @c (0, ∞) due to the + * square root of the discrimant term being dropped from + * the calculation. + */ + double const q = + -(b + sgn(b) * std::sqrt(discriminant)) / 2; roots.first = q / a; roots.second = c / q; diff --git a/lib/MaRC/Matrix.h b/lib/marc/Matrix.h similarity index 87% rename from lib/MaRC/Matrix.h rename to lib/marc/Matrix.h index 6c681997..ddbe4612 100644 --- a/lib/MaRC/Matrix.h +++ b/lib/marc/Matrix.h @@ -2,7 +2,7 @@ /** * @file Matrix.h * - * MaRC matrix class and operations. + * %MaRC matrix class and operations. * * Copyright (C) 2004, 2017-2018 Ossama Othman * @@ -27,7 +27,7 @@ #ifndef MARC_MATRIX_H #define MARC_MATRIX_H -#include "MaRC/Vector.h" +#include "marc/Vector.h" #include #include @@ -40,7 +40,7 @@ namespace MaRC { /** - * @class Matrix + * @class Matrix Matrix.h * * @brief Simple zero-based index matrix implementation. * @@ -50,7 +50,7 @@ namespace MaRC * This matrix implementation is designed to be fast (e.g. no * dynamic memory allocations when initializing or copying). It * is not super-optimized like some existing implementations but - * it is good enough for MaRC's purposes. Furthermore, it is + * it is good enough for %MaRC's purposes. Furthermore, it is * really only optimized for small matrices (e.g. 3x3). Much * larger matrices will still incur large matrix element copying * overhead. @@ -59,12 +59,21 @@ namespace MaRC * * @todo Look into using super-optimized third party matrix * implementations. + * + * @tparam T Matrix element type. It should be an arithmetic type + * such as an integer or floating point type. + * @tparam M The number of rows in the matrix. + * @tparam N The number of columns in the matrix. */ template class Matrix { public: + /** + * STL style container typedefs. + */ + //@{ typedef T value_type; typedef T element_type; typedef T & reference; @@ -73,6 +82,7 @@ namespace MaRC typedef Matrix transpose_type; typedef T * iterator; typedef T const * const_iterator; + //@} /// Constructor. Matrix() @@ -84,7 +94,7 @@ namespace MaRC } /** - * Construct @c Matrix from an initializer list. + * @brief Construct @c Matrix from an initializer list. * * This constructor allows a @c Matrix to be initialized like * so: @@ -122,40 +132,6 @@ namespace MaRC std::copy(std::cbegin(rhs), std::cend(rhs), this->begin()); } - /** - * Assign an initializer list to a @c Matrix. - * - * This constructor allows an initializer_list to be assigned - * to a @c Matrix list so: - * Matrix m{{0, 1}, - * {1, 2}, - * {2, 3}}; - */ - Matrix & operator=( - std::initializer_list> rhs) - { - if (rhs.size() != M || rhs.begin()->size() != N) { - throw std::out_of_range("Number of matrix / " - "initializer list " - "rows do not match."); - } - - auto dest = this->begin(); - - for (auto const & row : rhs) { - if (row.size() != N) { - throw std::out_of_range("Number of matrix / " - "initializer list " - "columns do not match."); - } - - std::copy(std::cbegin(row), std::cend(row), dest); - dest += N; // Next matrix row. - } - - return *this; - } - /// Copy assignment operator. Matrix & operator=(Matrix const & rhs) { @@ -169,7 +145,7 @@ namespace MaRC } /** - * Element accessor. + * @brief Element accessor. * * @note No bounds checking. * @@ -185,11 +161,11 @@ namespace MaRC } /** - * Const element accessor. + * @brief Const element accessor. * * @note No bounds checking. * - * @param[[n] row Zero-based matrix row. + * @param[in] row Zero-based matrix row. * @param[in] column Zero-based matrix column. * * @return Reference to @c const element at given @c Matrix @@ -202,7 +178,7 @@ namespace MaRC } /** - * Element accessor. + * @brief Element accessor. * * @note With bounds checking. * @@ -223,11 +199,11 @@ namespace MaRC } /** - * Const element accessor. + * @brief Const element accessor. * * @note With bounds checking. * - * @param[[n] row Zero-based matrix row. + * @param[in] row Zero-based matrix row. * @param[in] column Zero-based matrix column. * * @return Reference to @c const element at given @c Matrix @@ -245,7 +221,7 @@ namespace MaRC } /** - * Addition operator. + * @brief Addition operator. * * @param[in] rhs @c Matrix to be added to this one. * @@ -263,7 +239,7 @@ namespace MaRC } /** - * Subtraction operator. + * @brief Subtraction operator. * * @param[in] rhs @c Matrix to be substracted from this one. * @@ -281,7 +257,7 @@ namespace MaRC } /** - * Scalar multiplication operator. + * @brief Scalar multiplication operator. * * @param[in] rhs Scalar by which this @c Matrix will be * multiplied. @@ -291,6 +267,16 @@ namespace MaRC */ Matrix & operator*=(T rhs) { + /** + * @note @c this->matrix_ is a multi-dimensional array. + * Do not blindly use it as the range expression in + * the loop below. To do that we'd need a nested + * loop where the outer loop would iterate over the + * rows, and the inner loop would iterate over the + * columns. Just use @c *this as the range + * expression to allow for a simpler loop. The + * optimized compiled code should be quite tight. + */ for (auto & elem : *this) elem *= rhs; @@ -298,7 +284,7 @@ namespace MaRC } /** - * Get iterator to the beginning of the @c Matrix. + * @brief Get iterator to the beginning of the @c Matrix. * * @return Iterator to the beginning of the flattened form of * this @c Matrix. @@ -313,7 +299,8 @@ namespace MaRC } /** - * Get a @c const iterator to the beginning of the @c Matrix. + * @brief Get a @c const iterator to the beginning of the + * @c Matrix. * * @return @c const iterator to the beginning of the flattened * form of this @c Matrix. @@ -328,7 +315,7 @@ namespace MaRC } /** - * Get iterator to the end of the @c Matrix. + * @brief Get iterator to the end of the @c Matrix. * * @return Iterator to the end of the flattened form of this * @c Matrix. @@ -343,7 +330,7 @@ namespace MaRC } /** - * Get a @c const iterator to the endof the @c Matrix. + * @brief Get a @c const iterator to the endof the @c Matrix. * * @return @c const iterator to the end of the flattened * form of this @c Matrix. @@ -382,6 +369,7 @@ namespace MaRC return t; } + } // --------------------------------------------------------- diff --git a/lib/MaRC/Mercator.cpp b/lib/marc/Mercator.cpp similarity index 98% rename from lib/MaRC/Mercator.cpp rename to lib/marc/Mercator.cpp index 6f9b5d36..68765544 100644 --- a/lib/MaRC/Mercator.cpp +++ b/lib/marc/Mercator.cpp @@ -27,7 +27,10 @@ #include "Mathematics.h" #include "root_find.h" #include "OblateSpheroid.h" -#include "Log.h" + +#ifndef NDEBUG +// # include "Log.h" +#endif #include #include @@ -234,7 +237,7 @@ MaRC::Mercator::get_longitude(std::size_t i, std::size_t samples) const /** * @todo Verify that the shift by @c lo_lon below works as - * expected when it is non-zero (e.g. -C::pi). + * expected when it is non-zero (e.g. π). */ // Compute longitude at center of pixel. diff --git a/lib/MaRC/Mercator.h b/lib/marc/Mercator.h similarity index 90% rename from lib/MaRC/Mercator.h rename to lib/marc/Mercator.h index 584b578e..2b0bd7a4 100644 --- a/lib/MaRC/Mercator.h +++ b/lib/marc/Mercator.h @@ -25,7 +25,7 @@ #ifndef MARC_MERCATOR_H #define MARC_MERCATOR_H -#include +#include #include @@ -35,7 +35,7 @@ namespace MaRC class OblateSpheroid; /** - * @class Mercator + * @class Mercator Mercator.h * * @brief Mercator concrete map factory. * @@ -57,10 +57,10 @@ namespace MaRC { public: - /// @typedef Type returned from @c make_grid() method. + /// Type returned from @c make_grid() method. using typename MapFactory::grid_type; - /// @typedef Type of functor passed to @c plot_map() method. + /// Type of functor passed to @c plot_map() method. using typename MapFactory::plot_type; /// Constructor. @@ -82,7 +82,7 @@ namespace MaRC * @see @c MapFactory */ //@{ - virtual char const * projection_name() const; + virtual char const * projection_name() const override; //@} /** @@ -102,7 +102,7 @@ namespace MaRC */ virtual void plot_map(std::size_t samples, std::size_t lines, - plot_type plot) const; + plot_type plot) const override; /** * Create the Mercator map latitude/longitude grid. @@ -113,7 +113,7 @@ namespace MaRC std::size_t lines, double lat_interval, double lon_interval, - grid_type & grid) const; + grid_type & grid) const override; /// Orient longitude according to rotation direction /// (prograde/retrograde). diff --git a/lib/MaRC/MosaicImage.cpp b/lib/marc/MosaicImage.cpp similarity index 99% rename from lib/MaRC/MosaicImage.cpp rename to lib/marc/MosaicImage.cpp index 362e8cd8..d67ad6d2 100644 --- a/lib/MaRC/MosaicImage.cpp +++ b/lib/marc/MosaicImage.cpp @@ -25,8 +25,6 @@ #include "PhotoImage.h" #include "Mathematics.h" -#include - MaRC::MosaicImage::MosaicImage(list_type && images, average_type type) diff --git a/lib/MaRC/MosaicImage.h b/lib/marc/MosaicImage.h similarity index 69% rename from lib/MaRC/MosaicImage.h rename to lib/marc/MosaicImage.h index 43b7e7f4..c758f8be 100644 --- a/lib/MaRC/MosaicImage.h +++ b/lib/marc/MosaicImage.h @@ -25,8 +25,8 @@ #ifndef MARC_MOSAIC_IMAGE_H #define MARC_MOSAIC_IMAGE_H -#include -#include +#include +#include #include #include @@ -35,7 +35,7 @@ namespace MaRC { /** - * @class MosaicImage + * @class MosaicImage MosaicImage.h * * @brief Source image comprised of multiple @c PhotoImages. * @@ -46,14 +46,18 @@ namespace MaRC { public: + /** + * Type of list containing source images that comprise the + * mosaic. + */ using list_type = std::vector>; /** - * @enum AverageType + * @enum average_type * - * The type of averaging to be performed on data retrieved - * from multiple images that contain data at the given - * latitude and longitude. + * The type of averaging to be performed on physical data + * retrieved from multiple images that contain data at the + * given latitude and longitude. */ enum average_type { AVG_NONE, AVG_UNWEIGHTED, AVG_WEIGHTED }; @@ -67,25 +71,29 @@ namespace MaRC */ MosaicImage(list_type && images, average_type type); - /// Retrieve data from mosaic images. + /// Destructor. + virtual ~MosaicImage() = default; + + /// Retrieve physical data from mosaic images. /** - * Retrieve data from all mosaic images that have data at the - * given latitude and longitude. The configured data - * averaging strategy will be applied in cases where multiple - * images have data at the given longitude and latitude. + * Retrieve physical data from all mosaic images that have + * data at the given latitude and longitude. The configured + * data averaging strategy will be applied in cases where + * multiple images have data at the given longitude and + * latitude. * * @param[in] lat Planetocentric latitude in radians. * @param[in] lon Longitude in radians. - * @param[out] data Data retrieved from image. + * @param[out] data Physical data retrieved from image. * - * @retval true Data retrieved, - * @retval false No data retrieved. + * @retval true Physical data retrieved, + * @retval false No physical data retrieved. * * @see @c MaRC::SourceImage::read_data(); */ virtual bool read_data(double lat, double lon, - double & data) const; + double & data) const override; private: diff --git a/lib/MaRC/Mu0Image.cpp b/lib/marc/Mu0Image.cpp similarity index 97% rename from lib/MaRC/Mu0Image.cpp rename to lib/marc/Mu0Image.cpp index 49ee5682..e4b313ae 100644 --- a/lib/MaRC/Mu0Image.cpp +++ b/lib/marc/Mu0Image.cpp @@ -25,7 +25,7 @@ #include "BodyData.h" #include "Constants.h" -#include +#include MaRC::Mu0Image::Mu0Image(std::shared_ptr body, @@ -54,5 +54,7 @@ MaRC::Mu0Image::read_data_i(double lat, double lon, double & data) const lat, lon); + assert(data >= -1 && data <= 1); + return true; } diff --git a/lib/MaRC/Mu0Image.h b/lib/marc/Mu0Image.h similarity index 92% rename from lib/MaRC/Mu0Image.h rename to lib/marc/Mu0Image.h index c2f44da7..684b8c72 100644 --- a/lib/MaRC/Mu0Image.h +++ b/lib/marc/Mu0Image.h @@ -25,8 +25,8 @@ #ifndef MARC_MU0_IMAGE_H #define MARC_MU0_IMAGE_H -#include "MaRC/VirtualImage.h" -#include "MaRC/Export.h" +#include "marc/VirtualImage.h" +#include "marc/Export.h" #include @@ -36,7 +36,7 @@ namespace MaRC class BodyData; /** - * @class Mu0Image + * @class Mu0Image Mu0Image.h * * @brief Cosine of the incidence angle (i.e. μ0) * virtual image. @@ -69,6 +69,9 @@ namespace MaRC double scale, double offset); + /// Destructor. + virtual ~Mu0Image() = default; + private: /// Compute cosine of the incidence angle, μ0. @@ -77,7 +80,7 @@ namespace MaRC */ virtual bool read_data_i(double lat, double lon, - double & Data) const; + double & Data) const override; private: diff --git a/lib/MaRC/MuImage.cpp b/lib/marc/MuImage.cpp similarity index 97% rename from lib/MaRC/MuImage.cpp rename to lib/marc/MuImage.cpp index 93fc2ce1..fb0709b0 100644 --- a/lib/MaRC/MuImage.cpp +++ b/lib/marc/MuImage.cpp @@ -25,7 +25,7 @@ #include "BodyData.h" #include "Constants.h" -#include +#include MaRC::MuImage::MuImage(std::shared_ptr body, @@ -57,5 +57,7 @@ MaRC::MuImage::read_data_i(double lat, double lon, double & data) const lon, this->range_); + assert(data >= -1 && data <= 1); + return true; } diff --git a/lib/MaRC/MuImage.h b/lib/marc/MuImage.h similarity index 93% rename from lib/MaRC/MuImage.h rename to lib/marc/MuImage.h index c0a1ccd7..95c067f5 100644 --- a/lib/MaRC/MuImage.h +++ b/lib/marc/MuImage.h @@ -25,8 +25,8 @@ #ifndef MARC_MU_IMAGE_H #define MARC_MU_IMAGE_H -#include "MaRC/VirtualImage.h" -#include "MaRC/Export.h" +#include "marc/VirtualImage.h" +#include "marc/Export.h" #include @@ -36,7 +36,7 @@ namespace MaRC class BodyData; /** - * @class MuImage + * @class MuImage MuImage.h * * @brief Cosine of emission angle (i.e. μ) virtual image. * @@ -71,6 +71,9 @@ namespace MaRC double scale, double offset); + /// Destructor. + virtual ~MuImage() = default; + private: /// Compute cosine of emission angle, μ. @@ -79,7 +82,7 @@ namespace MaRC */ virtual bool read_data_i(double lat, double lon, - double & data) const; + double & data) const override; private: diff --git a/lib/MaRC/Notifier.cpp b/lib/marc/Notifier.cpp similarity index 100% rename from lib/MaRC/Notifier.cpp rename to lib/marc/Notifier.cpp diff --git a/lib/MaRC/Notifier.h b/lib/marc/Notifier.h similarity index 96% rename from lib/MaRC/Notifier.h rename to lib/marc/Notifier.h index f0800775..b1111d30 100644 --- a/lib/MaRC/Notifier.h +++ b/lib/marc/Notifier.h @@ -25,8 +25,8 @@ #ifndef MARC_NOTIFIER_H #define MARC_NOTIFIER_H -#include -#include +#include +#include #include #include @@ -38,7 +38,7 @@ namespace MaRC { /** - * @class Notifier + * @class Notifier Notifier.h * * @brief Map progress notifier. * @@ -50,6 +50,7 @@ namespace MaRC { public: + /// Convenience alias for the progress observer type. using observer_type = std::unique_ptr; /// Constructor diff --git a/lib/MaRC/NullGeometricCorrection.cpp b/lib/marc/NullGeometricCorrection.cpp similarity index 100% rename from lib/MaRC/NullGeometricCorrection.cpp rename to lib/marc/NullGeometricCorrection.cpp diff --git a/lib/MaRC/NullGeometricCorrection.h b/lib/marc/NullGeometricCorrection.h similarity index 77% rename from lib/MaRC/NullGeometricCorrection.h rename to lib/marc/NullGeometricCorrection.h index e9a99a5b..90e457ee 100644 --- a/lib/MaRC/NullGeometricCorrection.h +++ b/lib/marc/NullGeometricCorrection.h @@ -25,21 +25,22 @@ #ifndef MARC_NULL_GEOMETRIC_CORRECTION_H #define MARC_NULL_GEOMETRIC_CORRECTION_H -#include -#include +#include +#include namespace MaRC { /** - * @class NullGeometricCorrection + * @class NullGeometricCorrection NullGeometricCorrection.h * * @brief Null (no-op) geometric correction strategy. * * This geometric correction strategy is a no-op. It performs no * geometric correction. */ - class MARC_API NullGeometricCorrection : public GeometricCorrection + class MARC_API NullGeometricCorrection final + : public GeometricCorrection { public: @@ -53,8 +54,10 @@ namespace MaRC * abstract base class. */ //@{ - void image_to_object(double & line, double & sample) const; - void object_to_image(double & line, double & sample) const; + void image_to_object(double & line, + double & sample) const override; + void object_to_image(double & line, + double & sample) const override; //@} }; diff --git a/lib/MaRC/NullInterpolation.cpp b/lib/marc/NullInterpolation.cpp similarity index 96% rename from lib/MaRC/NullInterpolation.cpp rename to lib/marc/NullInterpolation.cpp index 63a12ddf..8d54f2b4 100644 --- a/lib/MaRC/NullInterpolation.cpp +++ b/lib/marc/NullInterpolation.cpp @@ -1,5 +1,5 @@ /** - * @file NullInterpolationStrategy.cpp + * @file NullInterpolation.cpp * * Copyright (C) 2004, 2017 Ossama Othman * diff --git a/lib/MaRC/NullInterpolation.h b/lib/marc/NullInterpolation.h similarity index 88% rename from lib/MaRC/NullInterpolation.h rename to lib/marc/NullInterpolation.h index 76fbe5d2..efd74a9f 100644 --- a/lib/MaRC/NullInterpolation.h +++ b/lib/marc/NullInterpolation.h @@ -25,15 +25,15 @@ #ifndef MARC_NULL_INTERPOLATION_H #define MARC_NULL_INTERPOLATION_H -#include "MaRC/InterpolationStrategy.h" -#include "MaRC/Export.h" +#include "marc/InterpolationStrategy.h" +#include "marc/Export.h" namespace MaRC { /** - * @class NullInterpolation + * @class NullInterpolation NullInterpolation.h * * @brief Null (no-op) interpolation strategy. * @@ -51,7 +51,7 @@ namespace MaRC virtual bool interpolate(double const *, double, double, - double &) const; + double &) const override; }; diff --git a/lib/MaRC/NullPhotometricCorrection.cpp b/lib/marc/NullPhotometricCorrection.cpp similarity index 100% rename from lib/MaRC/NullPhotometricCorrection.cpp rename to lib/marc/NullPhotometricCorrection.cpp diff --git a/lib/MaRC/NullPhotometricCorrection.h b/lib/marc/NullPhotometricCorrection.h similarity index 85% rename from lib/MaRC/NullPhotometricCorrection.h rename to lib/marc/NullPhotometricCorrection.h index 759c9a52..3adbcc3c 100644 --- a/lib/MaRC/NullPhotometricCorrection.h +++ b/lib/marc/NullPhotometricCorrection.h @@ -25,21 +25,21 @@ #ifndef MARC_NULL_PHOTOMETRIC_CORRECTION_H #define MARC_NULL_PHOTOMETRIC_CORRECTION_H -#include +#include namespace MaRC { /** - * @class NullPhotometricCorrection + * @class NullPhotometricCorrection NullPhotometricCorrection.h * * @brief Null (no-op) photometric correction strategy. * * This photometric correction strategy is a no-op. It performs * no photometric correction. */ - class MARC_API NullPhotometricCorrection + class MARC_API NullPhotometricCorrection final : public PhotometricCorrection { public: @@ -56,14 +56,15 @@ namespace MaRC * @see @c PhotometricCorrection::correct() */ //@{ - /// Perform photometric correction. /** + * @brief Perform photometric correction. + * * This particular implementation is a no-op. * * @return @c true in all cases. */ virtual bool correct(ViewingGeometry const & geometry, - double & data); + double & data) override; //@} }; diff --git a/lib/MaRC/OblateSpheroid.cpp b/lib/marc/OblateSpheroid.cpp similarity index 95% rename from lib/MaRC/OblateSpheroid.cpp rename to lib/marc/OblateSpheroid.cpp index 958ba4df..a3b0335d 100644 --- a/lib/MaRC/OblateSpheroid.cpp +++ b/lib/marc/OblateSpheroid.cpp @@ -24,12 +24,9 @@ #include "OblateSpheroid.h" #include "Vector.h" #include "Mathematics.h" -#include "Log.h" #include #include -#include -#include #include @@ -219,25 +216,23 @@ MaRC::OblateSpheroid::cos_phase(double sub_observ_lat, double MaRC::OblateSpheroid::M(double lat) { - double const fe2 = - this->first_eccentricity_ * this->first_eccentricity_; - double const sin_latg = std::sin(this->graphic_latitude(lat)); + double const fe2 = std::pow(this->first_eccentricity_, 2); + double const latg = this->graphic_latitude(lat); + double const sin2_latg = std::pow(std::sin(latg), 2); - return - this->eq_rad_ * (1 - fe2) - / std::pow(1 - fe2 * sin_latg * sin_latg, 1.5); + return + this->eq_rad_ * (1 - fe2) / std::pow(1 - fe2 * sin2_latg, 1.5); } double MaRC::OblateSpheroid::N(double lat) { - double const sin_latg = std::sin(this->graphic_latitude(lat)); + double const latg = this->graphic_latitude(lat); return this->eq_rad_ - / std::sqrt(1 - this->first_eccentricity_ - * this->first_eccentricity_ - * sin_latg * sin_latg); + / std::sqrt(1 - std::pow(this->first_eccentricity_, 2) + * std::pow(std::sin(latg), 2)); } int diff --git a/lib/MaRC/OblateSpheroid.h b/lib/marc/OblateSpheroid.h similarity index 90% rename from lib/MaRC/OblateSpheroid.h rename to lib/marc/OblateSpheroid.h index 5ad01b3e..a5f4d618 100644 --- a/lib/MaRC/OblateSpheroid.h +++ b/lib/marc/OblateSpheroid.h @@ -25,17 +25,18 @@ #ifndef MARC_OBLATE_SPHEROID_H #define MARC_OBLATE_SPHEROID_H -#include -#include -#include +#include +#include +#include namespace MaRC { + /// Internal convenience type. typedef Vector DVector; /** - * @class OblateSpheroid + * @class OblateSpheroid OblateSpheroid.h * * @brief Representation of a body modeled as an oblate spheroid. * @@ -96,22 +97,22 @@ namespace MaRC * class. */ //@{ - virtual double centric_radius(double lat) const; + virtual double centric_radius(double lat) const override; - virtual double centric_latitude(double latg) const; + virtual double centric_latitude(double latg) const override; - virtual double graphic_latitude(double lat) const; + virtual double graphic_latitude(double lat) const override; virtual double mu(double sub_observ_lat, double sub_observ_lon, double lat, double lon, - double range) const; + double range) const override; virtual double mu0(double sub_solar_lat, double sub_solar_lon, double lat, - double lon) const; + double lon) const override; virtual double cos_phase(double sub_observ_lat, double sub_observ_lon, @@ -119,7 +120,7 @@ namespace MaRC double sub_solar_lon, double lat, double lon, - double range) const; + double range) const override; //@} /// Radius of curvature of the meridian. diff --git a/lib/MaRC/Observer.h b/lib/marc/Observer.h similarity index 96% rename from lib/MaRC/Observer.h rename to lib/marc/Observer.h index 5b513d4d..75aace5c 100644 --- a/lib/MaRC/Observer.h +++ b/lib/marc/Observer.h @@ -25,7 +25,7 @@ #ifndef MARC_OBSERVER_H #define MARC_OBSERVER_H -#include +#include #include @@ -36,7 +36,7 @@ namespace MaRC { /** - * @class Observer + * @class Observer Observer.h * * @brief Map progress observer. * diff --git a/lib/MaRC/Orthographic.cpp b/lib/marc/Orthographic.cpp similarity index 88% rename from lib/MaRC/Orthographic.cpp rename to lib/marc/Orthographic.cpp index 686bdb97..db460bc9 100644 --- a/lib/MaRC/Orthographic.cpp +++ b/lib/marc/Orthographic.cpp @@ -45,9 +45,9 @@ MaRC::Orthographic::Orthographic ( OrthographicCenter const & center) : MapFactory() , body_(body) - , sub_observ_lat_(0) - , sub_observ_lon_(0) - , PA_(0) + , sub_observ_lat_(MaRC::validate_latitude(sub_observ_lat)) + , sub_observ_lon_(MaRC::validate_longitude(sub_observ_lon)) + , PA_(MaRC::validate_position_angle(PA)) , km_per_pixel_(-1) , sample_center_(std::numeric_limits::signaling_NaN()) , line_center_(std::numeric_limits::signaling_NaN()) @@ -55,51 +55,35 @@ MaRC::Orthographic::Orthographic ( , lon_at_center_(std::numeric_limits::signaling_NaN()) , polar_(false) { - if (sub_observ_lat >= -90 && sub_observ_lat <= 90) - this->sub_observ_lat_ = sub_observ_lat; + if (this->sub_observ_lon_ < 0) + this->sub_observ_lon_ += C::_2pi; - if (sub_observ_lon >= -360 && sub_observ_lon <= 360) { - this->sub_observ_lon_ = sub_observ_lon; - - if (this->sub_observ_lon_ < 0) - this->sub_observ_lon_ += 360; - } - - if (PA >= -360 && PA <= 360) - this->PA_ = PA; - - /** - * @todo Leverage @c MaRC::almost_equal() here. - */ - if (std::abs(std::abs(this->sub_observ_lat_) - 90) < 1e-5) { + constexpr int ulps = 4; + if (MaRC::almost_equal(std::abs(sub_observ_lat), 90., ulps)) { MaRC::info("assuming POLAR ORTHOGRAPHIC projection"); - if ((this->sub_observ_lat_ > 0 && this->body_->prograde()) - || (this->sub_observ_lat_ < 0 && !this->body_->prograde())) { + if ((sub_observ_lat > 0 && this->body_->prograde()) + || (sub_observ_lat < 0 && !this->body_->prograde())) { if (this->body_->prograde()) - this->PA_ = 180; + this->PA_ = C::pi; else this->PA_ = 0; } else { if (this->body_->prograde()) this->PA_ = 0; else - this->PA_ = 180; + this->PA_ = C::pi; } - if (this->sub_observ_lat_ > 0) - this->sub_observ_lat_ = 90; + if (sub_observ_lat > 0) + this->sub_observ_lat_ = C::pi_2; else - this->sub_observ_lat_ = -90; + this->sub_observ_lat_ = -C::pi_2; this->sub_observ_lon_ = 0; this->polar_ = true; } - this->sub_observ_lat_ *= C::degree; // Convert to radians - this->sub_observ_lon_ *= C::degree; - this->PA_ *= C::degree; - if (km_per_pixel > 0) this->km_per_pixel_ = km_per_pixel; @@ -113,7 +97,7 @@ MaRC::Orthographic::Orthographic ( MaRC::validate_latitude(center.sample_lat_center); this->lon_at_center_ = - MaRC::validate_latitude(center.line_lon_center); + MaRC::validate_longitude(center.line_lon_center); // Check if longitude at center (if supplied) is visible. @@ -122,13 +106,13 @@ MaRC::Orthographic::Orthographic ( // std::tan(this->sub_observ_lat_); double const cosine = - this->body_->eq_rad() * this->body_->eq_rad() - / this->body_->pol_rad() / this->body_->pol_rad() * - std::tan(this->lat_at_center_) * std::tan(this->sub_observ_lat_); + std::pow(this->body_->eq_rad() / this->body_->pol_rad(), 2) + * std::tan(this->lat_at_center_) + * std::tan(this->sub_observ_lat_); if (cosine < -1) { std::ostringstream s; - s << "Desired LATITUDE (" << this->lat_at_center_ / C::degree + s << "Desired LATITUDE (" << center.sample_lat_center << ") at center of image is not visible."; throw std::invalid_argument(s.str()); @@ -153,32 +137,29 @@ MaRC::Orthographic::Orthographic ( if (this->lon_at_center_ < lower || this->lon_at_center_ > upper) { std::ostringstream s; - s << "Desired LONGITUDE (" << this->lon_at_center_ / C::degree + s << "Desired LONGITUDE (" << center.line_lon_center << ") at center of image is not visible."; throw std::invalid_argument(s.str()); } double const shift = this->sub_observ_lon_ - this->lon_at_center_; + double const radius = + this->body_->centric_radius(this->lat_at_center_); - double pos[3]; + double pos[] = { + // X + radius * std::cos(this->lat_at_center_) * std::sin(shift), - if (this->body_->prograde()) - pos[0] = - this->body_->centric_radius(this->lat_at_center_) * - std::cos(this->lat_at_center_) * std::sin(shift); // X - else - pos[0] = - -this->body_->centric_radius(this->lat_at_center_) * - std::cos(this->lat_at_center_) * std::sin(shift); // X + // Y + -radius * std::cos(this->lat_at_center_) * std::cos(shift), - pos[1] = - -this->body_->centric_radius(this->lat_at_center_) - * std::cos(this->lat_at_center_) * std::cos(shift); // Y + // Z + radius * std::sin(this->lat_at_center_) + }; - pos[2] = - this->body_->centric_radius(this->lat_at_center_) - * std::sin(this->lat_at_center_); // Z + if (!this->body_->prograde()) + pos[0] = -pos[0]; // Centers in kilometers. this->sample_center_ = @@ -225,7 +206,14 @@ MaRC::Orthographic::plot_map(std::size_t samples, double const a2 = this->body_->eq_rad() * this->body_->eq_rad(); double const c2 = this->body_->pol_rad() * this->body_->pol_rad(); - double const diff = a2 - c2; + + /* + Reduce cancellation due to subtraction from being catastrophic + to benign by using the form (a-c)(a+c) instead of (a*a - c*c). + */ + double const diff = + (this->body_->eq_rad() - this->body_->pol_rad()) + * (this->body_->eq_rad() + this->body_->pol_rad()); // "a" coefficient of the Quadratic Formula. double const CA = diff --git a/lib/MaRC/Orthographic.h b/lib/marc/Orthographic.h similarity index 82% rename from lib/MaRC/Orthographic.h rename to lib/marc/Orthographic.h index 84cfd757..951b6a2b 100644 --- a/lib/MaRC/Orthographic.h +++ b/lib/marc/Orthographic.h @@ -25,7 +25,7 @@ #ifndef MARC_ORTHOGRAPHIC_H #define MARC_ORTHOGRAPHIC_H -#include +#include #include @@ -35,10 +35,17 @@ namespace MaRC class OblateSpheroid; struct OrthographicCenter; + /** + * @enum GeometryType + * + * @brief Body center geometry type. + * + * @todo Improve the orthographic center API. + */ enum GeometryType { DEFAULT, CENTER_GIVEN, LAT_LON_GIVEN }; /** - * @class Orthographic + * @class Orthographic Orthographic.h * * @brief Orthographic concrete map factory. * @@ -53,10 +60,10 @@ namespace MaRC { public: - /// @typedef Type of grid passed to @c plot_grid() method. + /// Type of grid passed to @c plot_grid() method. using typename MapFactory::grid_type; - /// @typedef Type of functor passed to @c plot_map() method. + /// Type of functor passed to @c plot_map() method. using typename MapFactory::plot_type; /// Constructor. @@ -94,7 +101,7 @@ namespace MaRC * @see @c MapFactory */ //@{ - virtual char const * projection_name() const; + virtual char const * projection_name() const override; //@} private: @@ -127,7 +134,7 @@ namespace MaRC */ virtual void plot_map(std::size_t samples, std::size_t lines, - plot_type plot) const; + plot_type plot) const override; /** * Create the Orthographic map latitude/longitude grid. @@ -138,7 +145,7 @@ namespace MaRC std::size_t lines, double lat_interval, double lon_interval, - grid_type & grid) const; + grid_type & grid) const override; private: @@ -179,7 +186,7 @@ namespace MaRC }; /** - * @struct OrthographicCenter + * @struct OrthographicCenter Orthographic.h * * @brief Center of body in orthographic projection. * @@ -188,8 +195,27 @@ namespace MaRC */ struct MARC_API OrthographicCenter { + /// Default Constructor. OrthographicCenter(); + /** + * @brief Constructor. + * + * @param[in] type Orthographic projection geometry + * type, e.g. @c LAT_LON_GIVEN. + * @param[in] sample_lat Sample or latitude at center of + * body. + * @param[in] line_lon Line or longitude at center of body. + */ + constexpr OrthographicCenter(GeometryType type, + double sample_lat, + double line_lon) noexcept + : geometry(type) + , sample_lat_center(sample_lat) + , line_lon_center(line_lon) + { + } + /// Type of body center geometry. GeometryType geometry; @@ -198,7 +224,6 @@ namespace MaRC /// Line or longitude at center of body. double line_lon_center; - }; } diff --git a/lib/MaRC/PhotoImage.cpp b/lib/marc/PhotoImage.cpp similarity index 99% rename from lib/MaRC/PhotoImage.cpp rename to lib/marc/PhotoImage.cpp index 7b9b6acb..b1cce818 100644 --- a/lib/MaRC/PhotoImage.cpp +++ b/lib/marc/PhotoImage.cpp @@ -179,7 +179,7 @@ MaRC::PhotoImage::read_data(double lat, char const * MaRC::PhotoImage::unit() const { - return this->config_->unit().c_str(); + return this->config_->unit(); } void diff --git a/lib/MaRC/PhotoImage.h b/lib/marc/PhotoImage.h similarity index 81% rename from lib/MaRC/PhotoImage.h rename to lib/marc/PhotoImage.h index bdd75dd4..4c2baa7b 100644 --- a/lib/MaRC/PhotoImage.h +++ b/lib/marc/PhotoImage.h @@ -25,8 +25,8 @@ #ifndef MARC_PHOTO_IMAGE_H #define MARC_PHOTO_IMAGE_H -#include -#include +#include +#include #include #include @@ -38,7 +38,7 @@ namespace MaRC class ViewingGeometry; /** - * @class PhotoImage + * @class PhotoImage PhotoImage.h * * @brief Concrete SourceImage strategy for mapping bodies in * photos. @@ -75,25 +75,25 @@ namespace MaRC /// Destructor. virtual ~PhotoImage() = default; - /// Retrieve data from source image. + /// Retrieve physical data from source image. /** - * Retrieve data from source image. The configured data - * interpolation strategy will be applied. + * Retrieve physical data from source image. The configured + * data interpolation strategy will be applied. * * @see MaRC::SourceImage::read_data(). */ virtual bool read_data(double lat, double lon, - double & data) const; + double & data) const override; - /// Retrieve data and weight from source image. + /// Retrieve physical data and weight from source image. /** - * Retrieve data and weight from source image. The configured - * data interpolation strategy will be applied. + * Retrieve physical data and weight from source image. The + * configured data interpolation strategy will be applied. * * @param[in] lat Planetocentric latitude in radians. * @param[in] lon Longitude in radians. - * @param[out] data Data retrieved from image. + * @param[out] data Physical data retrieved from image. * @param[in,out] weight Distance from pixel to closest edge * or blank pixel. * @param[in] scan Flag that determines if a data weight @@ -102,17 +102,22 @@ namespace MaRC * @c read_data() that does not return a * weight. * - * @retval true Data retrieved. - * @retval false No data retrieved. + * @retval true Physical data retrieved. + * @retval false No physical data retrieved. */ virtual bool read_data(double lat, double lon, double & data, std::size_t & weight, - bool scan = true) const; - + bool scan = true) const override; - virtual char const * unit() const; + /** + * @brief Get unit of physical data in the photo. + * + * @return Unit name, or empty string (@c "") if no unit is + * available. + */ + virtual char const * unit() const override; private: @@ -120,9 +125,9 @@ namespace MaRC * @brief Obtain data weight for given image pixel. * * Obtain the data weight based on how close the pixel at - * sample @a i and line @k is to the edge of the image or the - * sky if sky removal is enabled. For example, less weight is - * given to pixels close to an edge of the image. + * sample @a i and line @a k is to the edge of the image or + * the sky if sky removal is enabled. For example, less + * weight is given to pixels close to an edge of the image. * * @param[in] i Image pixel sample. * @param[in] k Image pixel line. diff --git a/lib/MaRC/PhotoImageParameters.cpp b/lib/marc/PhotoImageParameters.cpp similarity index 96% rename from lib/MaRC/PhotoImageParameters.cpp rename to lib/marc/PhotoImageParameters.cpp index b733b3f0..0eae182a 100644 --- a/lib/MaRC/PhotoImageParameters.cpp +++ b/lib/marc/PhotoImageParameters.cpp @@ -27,7 +27,6 @@ #include // #include -#include #ifndef MARC_DEFAULT_PHOTO_CORR_STRATEGY # define MARC_DEFAULT_PHOTO_CORR_STRATEGY MaRC::NullPhotometricCorrection @@ -48,7 +47,6 @@ MaRC::PhotoImageParameters::PhotoImageParameters() , interpolation_strategy_( std::make_unique()) , unit_() - , unit_comment_() , remove_sky_(false) { } @@ -150,12 +148,9 @@ MaRC::PhotoImageParameters::nibble_bottom(std::size_t n) } void -MaRC::PhotoImageParameters::unit(char const * u, char const * c) +MaRC::PhotoImageParameters::unit(std::string const & u) { - assert(u != nullptr && c != nullptr); - this->unit_ = u; - this->unit_comment_ = c; } void diff --git a/lib/MaRC/PhotoImageParameters.h b/lib/marc/PhotoImageParameters.h similarity index 89% rename from lib/MaRC/PhotoImageParameters.h rename to lib/marc/PhotoImageParameters.h index 6f0680bb..410a98b0 100644 --- a/lib/MaRC/PhotoImageParameters.h +++ b/lib/marc/PhotoImageParameters.h @@ -25,9 +25,9 @@ #ifndef MARC_PHOTO_IMAGE_PARAMETERS_H #define MARC_PHOTO_IMAGE_PARAMETERS_H -#include "MaRC/PhotometricCorrection.h" -#include "MaRC/InterpolationStrategy.h" -#include "MaRC/Export.h" +#include "marc/PhotometricCorrection.h" +#include "marc/InterpolationStrategy.h" +#include "marc/Export.h" #include #include @@ -37,7 +37,7 @@ namespace MaRC { /** - * @class PhotoImageParameters + * @class PhotoImageParameters PhotoImageParameters.h * * @brief Configuration parameters specific to @c PhotoImage. */ @@ -132,24 +132,13 @@ namespace MaRC * @brief Set the unit for the physical data in the image. * * @param[in] u Unit for the physical data in the image. - * @param[in] c Comment for the physical data unit. * * @see SourceImage::unit() */ - void unit(char const * u, char const * c); + void unit(std::string const & u); /// Get the unit for the physical data in the image. - std::string const & unit() const { return this->unit_; } - - /// Get the comment for the physical data unit. - std::string const & unit_comment() const - { - /** - * @todo The unit comment is currently unused. Do - * something with it, or remove it. - */ - return this->unit_comment_; - } + char const * unit() const { return this->unit_.c_str(); } /** * @brief Set sky removal variable @@ -205,9 +194,6 @@ namespace MaRC /// Unit of physical data in the image. std::string unit_; - /// Physical data unit comment. - std::string unit_comment_; - /// Should the sky removal mask be generated. bool remove_sky_; diff --git a/lib/MaRC/PhotometricCorrection.h b/lib/marc/PhotometricCorrection.h similarity index 95% rename from lib/MaRC/PhotometricCorrection.h rename to lib/marc/PhotometricCorrection.h index f54916a8..b111a3e6 100644 --- a/lib/MaRC/PhotometricCorrection.h +++ b/lib/marc/PhotometricCorrection.h @@ -25,7 +25,7 @@ #ifndef MARC_PHOTOMETRIC_CORRECTION_H #define MARC_PHOTOMETRIC_CORRECTION_H -#include +#include namespace MaRC @@ -33,7 +33,7 @@ namespace MaRC class ViewingGeometry; /** - * @class PhotometricCorrection + * @class PhotometricCorrection PhotometricCorrection.h * * @brief Photometric correction strategy abstract base class. * diff --git a/lib/MaRC/PolarStereographic.cpp b/lib/marc/PolarStereographic.cpp similarity index 99% rename from lib/MaRC/PolarStereographic.cpp rename to lib/marc/PolarStereographic.cpp index e272572d..8c0adaa0 100644 --- a/lib/MaRC/PolarStereographic.cpp +++ b/lib/marc/PolarStereographic.cpp @@ -25,7 +25,10 @@ #include "OblateSpheroid.h" #include "Constants.h" #include "root_find.h" -#include "Log.h" + +#ifndef NDEBUG +// # include "Log.h" +#endif #include #include diff --git a/lib/MaRC/PolarStereographic.h b/lib/marc/PolarStereographic.h similarity index 91% rename from lib/MaRC/PolarStereographic.h rename to lib/marc/PolarStereographic.h index 650ca523..31f09aef 100644 --- a/lib/MaRC/PolarStereographic.h +++ b/lib/marc/PolarStereographic.h @@ -25,7 +25,7 @@ #ifndef MARC_POLAR_STEREOGRAPHIC_H #define MARC_POLAR_STEREOGRAPHIC_H -#include +#include #include @@ -35,7 +35,7 @@ namespace MaRC class OblateSpheroid; /** - * @class PolarStereographic + * @class PolarStereographic PolarStereographic.h * * @brief Polar Stereographic concrete map factory. * @@ -50,10 +50,10 @@ namespace MaRC { public: - /// @typedef Type returned from @c make_grid() method. + /// Type returned from @c make_grid() method. typedef typename MapFactory::grid_type grid_type; - /// @typedef Type of functor passed to @c plot_map() method. + /// Type of functor passed to @c plot_map() method. using typename MapFactory::plot_type; /// Constructor. @@ -85,7 +85,7 @@ namespace MaRC * @see @c MapFactory */ //@{ - virtual char const * projection_name() const; + virtual char const * projection_name() const override; //@} /// @@ -105,7 +105,7 @@ namespace MaRC */ virtual void plot_map(std::size_t samples, std::size_t lines, - plot_type plot) const; + plot_type plot) const override; /** * Create the Polar Stereographic map latitude/longitude @@ -117,7 +117,7 @@ namespace MaRC std::size_t lines, double lat_interval, double lon_interval, - grid_type & grid) const; + grid_type & grid) const override; private: diff --git a/lib/MaRC/SimpleCylindrical.cpp b/lib/marc/SimpleCylindrical.cpp similarity index 62% rename from lib/MaRC/SimpleCylindrical.cpp rename to lib/marc/SimpleCylindrical.cpp index 2264fefa..92333823 100644 --- a/lib/MaRC/SimpleCylindrical.cpp +++ b/lib/marc/SimpleCylindrical.cpp @@ -21,15 +21,58 @@ * @author Ossama Othman */ -#include "MaRC/SimpleCylindrical.h" -#include "MaRC/Constants.h" -#include "MaRC/Validate.h" +#include "SimpleCylindrical.h" +#include "Constants.h" +#include "Validate.h" +#include "Mathematics.h" +#include "Log.h" #include #include #include +namespace +{ + /** + * @brief Get Simple Cylindrical map boundary latitude. + * + * Place supplied map boundary latitude in a form suitable for use + * by the %MaRC Simple Cylindrical projection. That entails + * converting it to radians, and potentially converting it to a + * planetographic latitude. + * + * This function is meant to be used during map initialization, + * and exists predominantly to allow for initialization of + * @c const map boundary latitude members. + * + * @param[in] degrees Planetocentric latitude in degrees. + * @param[in] body The body being mapped. + * @param[in] planetographic Whether or not latitude in the map + * will be planetographic. + * + * @return Latitude in radians. The returned latitude will be + * planetographic if the @a planetographic argument is + * @c true. + */ + double boundary_latitude(double degrees, + MaRC::BodyData const * body, + bool planetographic) + { + double latitude = MaRC::validate_latitude(degrees); + + // All latitudes fed to SimpleCylindrical are + // planetoCENTRIC. Convert to planetoGRAPHIC latitude if + // requested. + if (planetographic) + latitude = body->graphic_latitude(latitude); + + return latitude; + } +} + +// ------------------------------------------------------------------- + MaRC::SimpleCylindrical::SimpleCylindrical( std::shared_ptr body, double lo_lat, @@ -39,23 +82,27 @@ MaRC::SimpleCylindrical::SimpleCylindrical( bool graphic_lat) : MapFactory() , body_(body) - , lo_lat_(MaRC::validate_latitude(lo_lat)) - , hi_lat_(MaRC::validate_latitude(hi_lat)) + , lo_lat_(boundary_latitude(lo_lat, body_.get(), graphic_lat)) + , hi_lat_(boundary_latitude(hi_lat, body_.get(), graphic_lat)) , lo_lon_(MaRC::validate_longitude(lo_lon)) , hi_lon_(MaRC::validate_longitude(hi_lon)) , graphic_lat_(graphic_lat) { - // All latitudes are fed to SimpleCylindrical as CENTRIC. - // Convert to GRAPHIC latitude if requested. - if (graphic_lat) { - this->lo_lat_ = this->body_->graphic_latitude(this->lo_lat_); - this->hi_lat_ = this->body_->graphic_latitude(this->hi_lat_); - } - // Set lower longitude to equivalent longitude less than upper - // longitude to make sure longitude range is computed correctly. + // longitude or add 360 degrees to the upper longitude if it is + // equal to the lower longitude (i.e. full 360 degree range) to + // make sure longitude range is computed correctly. + constexpr int ulps = 2; if (this->lo_lon_ > this->hi_lon_) this->lo_lon_ -= C::_2pi; + else if (MaRC::almost_equal(this->lo_lon_, this->hi_lon_, ulps) + || (MaRC::almost_zero(this->lo_lon_, ulps) + && MaRC::almost_zero(this->hi_lon_, ulps))) { + this->hi_lon_ += C::_2pi; + + MaRC::info("lower and upper map longitudes are the same"); + MaRC::info("assuming 360 degree longitude range"); + } } char const * @@ -127,6 +174,12 @@ MaRC::SimpleCylindrical::plot_grid(std::size_t samples, // Sample-to-longitude ratio. double const sr = samples / (hi_lon - lo_lon); + /** + * @todo Why do we count down grid longitudes from 360 instead of + * counting up from 0? As is, we are plotting longitude + * lines in the half-open interval (0, 360] instead of + * [0, 360). Aren't they equivalent? + */ // Draw longitude lines. for (double m = 360; m > 0; m -= lon_interval) { // lo_lon_2 is a work-around for lo_lon_ > hi_lon_ problems diff --git a/lib/MaRC/SimpleCylindrical.h b/lib/marc/SimpleCylindrical.h similarity index 90% rename from lib/MaRC/SimpleCylindrical.h rename to lib/marc/SimpleCylindrical.h index c4f56502..26c95d2c 100644 --- a/lib/MaRC/SimpleCylindrical.h +++ b/lib/marc/SimpleCylindrical.h @@ -26,8 +26,8 @@ #ifndef MARC_SIMPLE_CYLINDRICAL_H #define MARC_SIMPLE_CYLINDRICAL_H -#include -#include +#include +#include #include @@ -36,7 +36,7 @@ namespace MaRC { /** - * @class SimpleCylindrical + * @class SimpleCylindrical SimpleCylindrical.h * * @brief Simple cylindrical concrete map factory. * @@ -51,10 +51,10 @@ namespace MaRC { public: - /// @typedef Type of grid passed to @c plot_grid() method. + /// Type of grid passed to @c plot_grid() method. using typename MapFactory::grid_type; - /// @typedef Type of functor passed to @c plot_map() method. + /// Type of functor passed to @c plot_map() method. using typename MapFactory::plot_type; /// Constructor. @@ -90,7 +90,7 @@ namespace MaRC * @see @c MapFactory */ //@{ - virtual char const * projection_name() const; + virtual char const * projection_name() const override; //@} private: @@ -102,7 +102,7 @@ namespace MaRC */ virtual void plot_map(std::size_t samples, std::size_t lines, - plot_type plot) const; + plot_type plot) const override; /** * Create the Simple Cylindrical map latitude/longitude grid. @@ -113,7 +113,7 @@ namespace MaRC std::size_t lines, double lat_interval, double lon_interval, - grid_type & grid) const; + grid_type & grid) const override; /// Orient longitude according to rotation direction /// (prograde/retrograde). @@ -146,10 +146,10 @@ namespace MaRC std::shared_ptr const body_; /// Lower latitude in simple cylindrical map. - double lo_lat_; + double const lo_lat_; /// Upper latitude in simple cylindrical map. - double hi_lat_; + double const hi_lat_; /// Lower longitude in simple cylindrical map. double lo_lon_; diff --git a/lib/MaRC/SourceImage.cpp b/lib/marc/SourceImage.cpp similarity index 100% rename from lib/MaRC/SourceImage.cpp rename to lib/marc/SourceImage.cpp diff --git a/lib/MaRC/SourceImage.h b/lib/marc/SourceImage.h similarity index 81% rename from lib/MaRC/SourceImage.h rename to lib/marc/SourceImage.h index 15b16123..8f08759f 100644 --- a/lib/MaRC/SourceImage.h +++ b/lib/marc/SourceImage.h @@ -26,15 +26,17 @@ #ifndef MARC_SOURCE_IMAGE_H #define MARC_SOURCE_IMAGE_H -#include +#include + #include namespace MaRC { + /** - * @class SourceImage + * @class SourceImage SourceImage.h * * @brief Abstract base class for all images to be mapped. * @@ -54,16 +56,15 @@ namespace MaRC /// Destructor. virtual ~SourceImage() = default; - /// Retrieve data from source image. /** - * Retrieve data from source image. + * @brief Retrieve physical data from source image. * * @param[in] lat Planetocentric latitude in radians. * @param[in] lon Longitude in radians. - * @param[out] data Data retrieved from image. + * @param[out] data Physical data retrieved from image. * - * @retval true Data retrieved. - * @retval false No data retrieved. + * @retval true Physical data retrieved. + * @retval false No physical data retrieved. */ virtual bool read_data(double lat, double lon, @@ -71,23 +72,23 @@ namespace MaRC /// Retrieve data and weight from source image. /** - * Retrieve data and weight from source image. The default - * implementation merely ignores the @a weight and @a scan - * arguments, and forwards the call to the concrete + * Retrieve physical data and weight from source image. The + * default implementation merely ignores the @a weight and + * @a scan arguments, and forwards the call to the concrete * implementation of @c read_data(). Subclasses should * override this method if they will provide a @a weight along * with @a data. * * @param[in] lat Planetocentric latitude in radians. * @param[in] lon Longitude in radians. - * @param[out] data Data retrieved from image. + * @param[out] data Physical data retrieved from image. * @param[in,out] weight Distance from pixel to closest edge * or blank pixel. * @param[in] scan Flag that determines if a data weight * scan is performed.. * - * @retval true Data retrieved. - * @retval false No data retrieved. + * @retval true Physical data retrieved. + * @retval false No physical data retrieved. */ virtual bool read_data(double lat, double lon, @@ -98,7 +99,7 @@ namespace MaRC /** * @brief Unit of physical data. * - * Get the units of the physical data, i.e. image data that + * Get the unit of the physical data, i.e. image data that * has been scaled and offset according to the following * equation: * diff --git a/lib/MaRC/Validate.h b/lib/marc/Validate.h similarity index 93% rename from lib/MaRC/Validate.h rename to lib/marc/Validate.h index 94afa7b5..2d39555e 100644 --- a/lib/MaRC/Validate.h +++ b/lib/marc/Validate.h @@ -28,9 +28,10 @@ #ifndef MARC_VALIDATE_H #define MARC_VALIDATE_H -#include "MaRC/Constants.h" +#include "marc/Constants.h" #include +#include namespace MaRC @@ -50,7 +51,7 @@ namespace MaRC */ inline double validate_latitude(double lat) { - if (lat < -90 || lat > 90) + if (std::isnan(lat) || lat < -90 || lat > 90) throw std::invalid_argument("invalid latitude"); return lat * C::degree; @@ -70,7 +71,7 @@ namespace MaRC */ inline double validate_longitude(double lon) { - if (lon < -360 || lon > 360) + if (std::isnan(lon) || lon < -360 || lon > 360) throw std::invalid_argument("invalid longitude"); // We don't shift negative longitudes to the equivalent @@ -95,7 +96,7 @@ namespace MaRC */ inline double validate_position_angle(double north) { - if (north < -360 || north > 360) + if (std::isnan(north) || north < -360 || north > 360) throw std::invalid_argument("invalid position angle"); return north * C::degree; diff --git a/lib/MaRC/Vector.h b/lib/marc/Vector.h similarity index 69% rename from lib/MaRC/Vector.h rename to lib/marc/Vector.h index 25254764..b31e0732 100644 --- a/lib/MaRC/Vector.h +++ b/lib/marc/Vector.h @@ -1,8 +1,8 @@ // -*- C++ -*- /** - * @file Vector.h + * @file marc/Vector.h * - * MaRC mathematical vector class and operations. + * %MaRC mathematical vector class and operations. * * Copyright (C) 2004, 2017-2018 Ossama Othman * @@ -27,9 +27,10 @@ #ifndef MARC_VECTOR_H #define MARC_VECTOR_H -#include "MaRC/Mathematics.h" +#include "marc/details/vector.h" #include +#include #include #include #include @@ -40,18 +41,27 @@ namespace MaRC { /** - * @class Vector + * @class Vector Vector.h * * @brief Zero-based index mathematical vector implementation. * * This is a simple zero-based index mathematical vector * implementation with @a M rows. + * + * @tparam T Vector element type. It should be an arithmetic type + * such as an integer or floating point type. + * @tparam M The number of dimensions (rows) in the vector, i.e an + * @a M -dimensional vector. */ template class Vector { public: + /** + * STL style container typedefs. + */ + //@{ typedef T value_type; typedef T element_type; typedef T & reference; @@ -59,9 +69,10 @@ namespace MaRC typedef Vector vector_type; typedef T * iterator; typedef T const * const_iterator; + //@} /** - * Default constructor. + * @brief Default constructor. * * Initialize the elements of the vector to the default value, * i.e. @c T(), which is 0 for arithmetic types. @@ -75,11 +86,32 @@ namespace MaRC } /** - * Construct @c Vector from an initializer list. + * @brief Construct @c Vector from a parameter pack. * - * This constructor allows a @c Vector to be initialized like - * so: - * Vector m{{0, 1, 2}}; + * This constructor allows a @c Vector to be direct + * initialized like so: + * @code + * Vector m(0, 1, 2); // direct initialization + * @endcode + */ + template + constexpr Vector(Args ... args) + : vector_{T(args) ...} + { + } + + /** + * @brief Construct @c Vector from an initializer list. + * + * This constructor allows a @c Vector to be list initialized + * like so: + * @code + * Vector m{0, 1, 2}; // direct-list-initialization + * @endcode + * or: + * @code + * Vector m = {0, 1, 2}; // copy-list-initialization + * @endcode */ Vector(std::initializer_list rhs) { @@ -98,24 +130,6 @@ namespace MaRC std::copy(std::cbegin(rhs), std::cend(rhs), this->begin()); } - /** - * Construct @c Vector from an initializer list. - * - * This constructor allows a @c Vector to be initialized like - * so: - * Vector m{{0, 1, 2}}; - */ - Vector & operator=(std::initializer_list rhs) - { - if (rhs.size() != M) { - throw std::out_of_range("Number of vector / " - "initializer list " - "elements do not match."); - } - - std::copy(std::cbegin(rhs), std::cend(rhs), this->begin()); - } - /// Copy assignment operator. Vector & operator=(Vector const & rhs) { @@ -125,7 +139,7 @@ namespace MaRC } /** - * Element accessor. + * @brief Element accessor. * * @note No bounds checking. * @@ -139,7 +153,7 @@ namespace MaRC } /** - * Const element accessor. + * @brief Const element accessor. * * @note No bounds checking. * @@ -154,7 +168,7 @@ namespace MaRC } /** - * Element accessor. + * @brief Element accessor. * * @note With bounds checking. * @@ -167,11 +181,11 @@ namespace MaRC if (row >= M) throw std::out_of_range("Out of range vector index"); - return this->vector_[row]; + return this->vector_[row]; } /** - * Const element accessor. + * @brief Const element accessor. * * @note With bounds checking. * @@ -189,7 +203,7 @@ namespace MaRC } /** - * Get iterator to the beginning of the @c Vector. + * @brief Get iterator to the beginning of the @c Vector. * * @return Iterator to the beginning of this @c Vector. * @@ -203,7 +217,8 @@ namespace MaRC } /** - * Get a @c const iterator to the beginning of the @c Vector. + * @brief Get a @c const iterator to the beginning of the + * @c Vector. * * @return @c const iterator to the beginning of of this * @c Vector. @@ -218,7 +233,7 @@ namespace MaRC } /** - * Get iterator to the end of the @c Vector. + * @brief Get iterator to the end of the @c Vector. * * @return Iterator to the end of of this @c Vector. * @@ -232,7 +247,7 @@ namespace MaRC } /** - * Get @c const iterator to the end of the @c Vector. + * @brief Get @c const iterator to the end of the @c Vector. * * @return @c const iterator to the end of of this @c Vector. * @@ -246,7 +261,7 @@ namespace MaRC } /** - * Addition operator. + * @brief Addition operator. * * @param[in] rhs @c Vector to be added to this one. * @@ -264,7 +279,7 @@ namespace MaRC } /** - * Subtraction operator. + * @brief Subtraction operator. * * @param[in] rhs @c Vector to be subtracted from this one. * @@ -282,7 +297,7 @@ namespace MaRC } /** - * Scalar multiplication operator. + * @brief Scalar multiplication operator. * * @param[in] rhs Scalar by which this @c Vector will be * multiplied. @@ -292,124 +307,54 @@ namespace MaRC */ Vector & operator*=(T rhs) { - for (auto & elem : *this) + for (auto & elem : this->vector_) elem *= rhs; return *this; } - private: - - /// Underlying vector array. - T vector_[M]; - }; - - /// Obtain magnitude of vector. - /** - * This generalized implementation can return the magnitude of a - * vector with an arbitrary number of rows - * - * @param[in] v Vector for which the magnitude will be - * calculated. - * - * @return Magnitude of vector @a v. - * - * @relates MaRC::Vector - */ - template - auto magnitude(Vector const & v) - { - double const m = 0; - /** - * @bug This implementation is subject to overflow or - * underflow. + * @brief Obtain magnitude (norm) of this vector. + * + * @todo Should we rename this method to @c norm() to be + * consistent with linear algebra conventions? + * + * @return Magnitude of this vector. */ - for (auto i = 0; i < M; ++i) - m += v[i] * v[i]; - - return std::sqrt(m); - } - - /// Obtain magnitude of vector with three rows. - /** - * This implementation avoids overflow and underflow when - * calculating the magnitude of vectors with three rows. - * - * @param[in] v Vector for which the magnitude will be - * calculated. - * - * @return Magnitude of vector @a v. - * - * @relates MaRC::Vector - */ - template - auto magnitude(Vector const & v) - { - return MaRC::hypot(v[0], v[1], v[2]); - } + double magnitude() const + { + return details::magnitude(this->vector_); + } - /// Obtain magnitude of vector with two rows. - /** - * This implementation avoids overflow and underflow when - * calculating the magnitude of vectors with two rows. - * - * @param[in] v Vector for which the magnitude will be - * calculated. - * - * @return Magnitude of vector @a v. - * - * @relates MaRC::Vector - */ - template - auto magnitude(Vector const & v) - { - return std::hypot(v[0], v[1]); - } + /** + * @brief Convert vector to a unit vector. + * + * @attention This function requires that the vector @a v contain + * floating point values since it is not possible to + * store fractional values in an integer. + */ + void to_unit_vector() + { + // This method will only work for integer types if the + // vector is already a unit vector (e.g. {0, 0, 1}). + static_assert(std::is_floating_point::value, + "to_unit_vector() cannot work reliably " + "for integer typed vectors."); - /// Obtain magnitude of vector with one row. - /** - * This implementation returns the magnitude of vector with one - * row. - * - * @param[in] v Vector for which the magnitude will be - * calculated. - * - * @return Magnitude of vector @a v. - * - * @relates MaRC::Vector - */ - template - auto magnitude(Vector const & v) - { - return v[0]; - } + auto const mag = this->magnitude(); - /// Convert a vector to a unit vector. - /** - * @param[in,out] v Vector to convert to a unit vector. - * - * @attention This function requires that the vector @a v contain - * floating point values since it is not possible to - * store fractional values in an integer. - * - * @relates MaRC::Vector - */ - template - void to_unit_vector(Vector & v) - { - static_assert(std::is_floating_point::value, - "MaRC::to_unit_vector() cannot work as expected " - "for integer typed vectors."); + for (auto & elem : this->vector_) + elem /= mag; + } - auto const mag = MaRC::magnitude(v); + private: - for(std::size_t i = 0; i < M; ++i) - v[i] /= mag; - } + /// Underlying vector array. + T vector_[M]; + }; - /// Obtain dot product of two vectors. /** + * @brief Obtain dot product of two vectors. * Given two vectors @a a and @a b, calculate their dot product. * * @param[in] a First vector operand. @@ -449,7 +394,7 @@ MaRC::Vector const operator+(MaRC::Vector const & lhs, } /** - * @brief Vector subtraction operator + * @brief Vector subtraction operator. * * @relates MaRC::Vector */ @@ -464,7 +409,7 @@ MaRC::Vector const operator-(MaRC::Vector const & lhs, } /** - * Vector/scalar multiplication operator + * @brief Vector/scalar multiplication operator. * * @relates MaRC::Vector */ @@ -479,7 +424,7 @@ MaRC::Vector const operator*(MaRC::Vector const & V, } /** - * Vector/scalar multiplication operator + * @brief Vector/scalar multiplication operator. * * @relates MaRC::Vector */ @@ -524,7 +469,7 @@ bool operator!=(MaRC::Vector const & lhs, // --------------------------------------------------------- /** - * @brief Stream insertion operator + * @brief Stream insertion operator. * * @relates MaRC::Vector */ diff --git a/lib/MaRC/ViewingGeometry.cpp b/lib/marc/ViewingGeometry.cpp similarity index 91% rename from lib/MaRC/ViewingGeometry.cpp rename to lib/marc/ViewingGeometry.cpp index 7996f980..b60d2fb0 100644 --- a/lib/MaRC/ViewingGeometry.cpp +++ b/lib/marc/ViewingGeometry.cpp @@ -31,9 +31,9 @@ #include "config.h" // For NDEBUG /** - * @todo Should this be an equivalent MaRC include directive? + * @todo Should this be an equivalent %MaRC include directive? */ -#include +#include #include #include @@ -97,7 +97,7 @@ namespace original[1], computed[1], original[2], computed[2], "", - MaRC::magnitude(original), MaRC::magnitude(computed), + original.magnitude(), computed.magnitude(), ""); } #endif @@ -309,7 +309,7 @@ MaRC::ViewingGeometry::finalize_setup(std::size_t samples, (this->line_center_ - this->OA_l_) * this->km_per_pixel_; // Since line numbers increase top to bottom (e.g. VICAR images) - double const mag = MaRC::magnitude(range_O); + double const mag = range_O.magnitude(); // Perpendicular distance from observer to image plane. this->normal_range_ = @@ -332,20 +332,20 @@ MaRC::ViewingGeometry::finalize_setup(std::size_t samples, double const radius = this->body_->centric_radius(this->lat_at_center_); - DVector r0; - r0[0] = radius * std::cos(this->lat_at_center_) * std::sin(lon); - r0[1] = -radius * std::cos(this->lat_at_center_) * std::cos(lon); - r0[2] = radius * std::sin(this->lat_at_center_); + DVector const r0( + radius * std::cos(this->lat_at_center_) * std::sin(lon), + -radius * std::cos(this->lat_at_center_) * std::cos(lon), + radius * std::sin(this->lat_at_center_)); DVector const OA_prime(r0 - this->range_b_); DVector OA_hat(OA_prime); - MaRC::to_unit_vector(OA_hat); + OA_hat.to_unit_vector(); // Dot product. double const dp = MaRC::dot_product(r0, OA_hat); - DVector r_OA(dp * OA_hat); + DVector const r_OA(dp * OA_hat); // Optical axis in body coordinates DVector const OpticalAxis(OA_prime - r_OA); @@ -373,7 +373,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_o, DMatrix & body2observ) { DVector r_o(range_o); - MaRC::to_unit_vector(r_o); + r_o.to_unit_vector(); // Compute transformation matrices DVector rotated; @@ -418,7 +418,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_o, observ2body = o2b; double diff_magnitude = - MaRC::magnitude(this->range_b_ - o2b * range_o); + (this->range_b_ - o2b * range_o).magnitude(); // ----------- TRY THE SECOND ROOT ------------- r_o = temp2; // Reset to value of vector after first rotation @@ -436,7 +436,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_o, * Geometry::RotYMatrix(-this->position_angle_)); double const test_diff_magnitude = - MaRC::magnitude(this->range_b_ - o2b * range_o); + (this->range_b_ - o2b * range_o).magnitude(); if (diff_magnitude > test_diff_magnitude) { diff_magnitude = test_diff_magnitude; @@ -444,7 +444,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_o, } double const percent_diff = - diff_magnitude / MaRC::magnitude(this->range_b_) * 100; + diff_magnitude / this->range_b_.magnitude() * 100; static constexpr double tolerance = 1e-8; if (percent_diff > tolerance) { @@ -482,7 +482,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_o, Ztwist / C::degree); // North pole unit vector. - DVector const body_north {0, 0, 1}; + constexpr DVector body_north(0, 0, 1); // North pole vector in camera (observer) coordinates. DVector const camera_north(body2observ * body_north); @@ -508,45 +508,37 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_b, DMatrix & observ2body, DMatrix & body2observ) { - double SubLatMod[2]; - - DVector NPole, rotated; - DVector OA_O; - - // Unit vector representing North pole in body coordinates - NPole[2] = 1; + // Unit vector representing North pole in body coordinates. + constexpr DVector body_north(0, 0, 1); - /** - * @todo Shouldn't this be @c OA_O[1] @c = @c -MaRC::magnitude(OA) ? - */ - // OA_O is the optical axis vector in observer coordinates - OA_O[1] = MaRC::magnitude(OA); // Magnitude of optical axis. + // OA_O is the optical axis vector in observer coordinates. + DVector const OA_O(0, + /** + * @todo Shouldn't this be @c -OA.magnitude() ? + */ + OA.magnitude(), + 0); DVector UnitOpticalAxis(OA); // Optical axis in body coordinates - MaRC::to_unit_vector(UnitOpticalAxis); + UnitOpticalAxis.to_unit_vector(); // Cosine of the angle between the North pole and the optical // axis. No need to divide by the product of the vector // magnitudes since they're both unit vectors (magnitudes of 1). - double const dotProd = MaRC::dot_product(NPole, UnitOpticalAxis); + double const dotProd = MaRC::dot_product(body_north, UnitOpticalAxis); - /** - * @todo Shouldn't this be @c (C::pi_2 @c - @c std::acos(dotProd)) ? - */ - SubLatMod[0] = std::asin(-dotProd); // Angle between equatorial - // plane and OA. - - DVector R_b(range_b); - MaRC::to_unit_vector(R_b); + double SubLatMod[2]; /** - * @bug This value is the same as the one computed above. + * @todo Shouldn't this be @c (C::pi_2 @c - @c std::acos(dotProd)) ? */ // Try first possibility SubLatMod[0] = std::asin(-dotProd); // Angle between equatorial // plane and OA. + + DVector rotated; Geometry::RotX(-SubLatMod[0], range_b, rotated); - R_b = rotated; + DVector R_b = rotated; double const Ztwist1 = std::atan2(R_b[0], -R_b[1]); @@ -557,8 +549,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_b, observ2body = o2b; - double diff_magnitude = - MaRC::magnitude(OA_O - o2b * UnitOpticalAxis); + double diff_magnitude = (OA - o2b * OA_O).magnitude(); /** * @todo This seems like a hack. Why do we need to check a second @@ -582,10 +573,9 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_b, double Ztwist, SubLatModified; #endif /* !NDEBUG */ - if (diff_magnitude > MaRC::magnitude(OA_O - - o2b * UnitOpticalAxis)) { - diff_magnitude = - MaRC::magnitude(OA_O - o2b * UnitOpticalAxis); + double const diffmag = (OA - o2b * OA_O).magnitude(); + if (diff_magnitude > diffmag) { + diff_magnitude = diffmag; observ2body = o2b; #ifndef NDEBUG @@ -598,7 +588,7 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_b, } double const percent_diff = - diff_magnitude / MaRC::magnitude(UnitOpticalAxis) * 100; + diff_magnitude / OA_O.magnitude() * 100; static constexpr double tolerance = 1e-8; @@ -644,9 +634,6 @@ MaRC::ViewingGeometry::rot_matrices(DVector const & range_b, SubLatModified / C::degree, Ztwist / C::degree); - // North pole unit vector. - DVector const body_north{0, 0, 1}; - // North pole vector in camera (observer) coordinates. DVector const camera_north(body2observ * body_north); @@ -876,18 +863,17 @@ MaRC::ViewingGeometry::latlon2pix(double lat, // Vector from center of the body to a point at the given latitude // and longitude on the surface of the body in the body coordinate // system. - DVector Coord; - Coord[0] = radius * std::cos(lat) * std::sin(lon); - Coord[1] = -radius * std::cos(lat) * std::cos(lon); - Coord[2] = radius * std::sin(lat); + DVector const coord(radius * std::cos(lat) * std::sin(lon), + -radius * std::cos(lat) * std::cos(lon), + radius * std::sin(lat)); - DVector const Obs(Coord - this->range_b_); + DVector const obs(coord - this->range_b_); // Convert to observer coordinates. - DVector const Rotated(this->body2observ_ * Obs); + DVector const rotated(this->body2observ_ * obs); /** - * @todo Rotated[1] should never be larger than + * @todo rotated[1] should never be larger than * @c normal_range_ since we verified that the point at the * given latitude and longitude is visible before getting * here. If that is a correct assumption figure out what is @@ -901,12 +887,12 @@ MaRC::ViewingGeometry::latlon2pix(double lat, * indeed be visible to the observer, and still be "behind" * the image plane. Confirm. */ - // if (Rotated[1] > this->normal_range_) + // if (rotated[1] > this->normal_range_) // return false; // On other side of image plane / body. // Drop the "y" component since it is zero in the image plane. - x = Rotated[0] / Rotated[1] * this->focal_length_pixels_; - z = Rotated[2] / Rotated[1] * this->focal_length_pixels_; + x = rotated[0] / rotated[1] * this->focal_length_pixels_; + z = rotated[2] / rotated[1] * this->focal_length_pixels_; // Convert from object space to image space. this->geometric_correction_->object_to_image(z, x); @@ -934,10 +920,7 @@ MaRC::ViewingGeometry::pix2latlon(double sample, // --------------------------------------------- // Convert from observer coordinates to body coordinates - DVector coord; - coord[0] = sample; - coord[1] = 0; - coord[2] = line; + DVector const coord(sample, 0, line); // Do the transformation DVector rotated(this->observ2body_ * coord); diff --git a/lib/MaRC/ViewingGeometry.h b/lib/marc/ViewingGeometry.h similarity index 99% rename from lib/MaRC/ViewingGeometry.h rename to lib/marc/ViewingGeometry.h index edab578d..1e6fda76 100644 --- a/lib/MaRC/ViewingGeometry.h +++ b/lib/marc/ViewingGeometry.h @@ -25,9 +25,9 @@ #ifndef MARC_VIEWING_GEOMETRY_H #define MARC_VIEWING_GEOMETRY_H -#include "MaRC/Geometry.h" -#include "MaRC/GeometricCorrection.h" -#include "MaRC/Export.h" +#include "marc/Geometry.h" +#include "marc/GeometricCorrection.h" +#include "marc/Export.h" #include #include @@ -40,7 +40,7 @@ namespace MaRC class GeometricCorrection; /** - * @class ViewingGeometry + * @class ViewingGeometry ViewingGeometry.h * * @brief Viewing geometry necessary to go from latitude/longitude * to image pixel. diff --git a/lib/MaRC/VirtualImage.cpp b/lib/marc/VirtualImage.cpp similarity index 100% rename from lib/MaRC/VirtualImage.cpp rename to lib/marc/VirtualImage.cpp diff --git a/lib/marc/VirtualImage.h b/lib/marc/VirtualImage.h new file mode 100644 index 00000000..ec229ef2 --- /dev/null +++ b/lib/marc/VirtualImage.h @@ -0,0 +1,200 @@ +// -*- C++ -*- +/** + * @file VirtualImage.h + * + * Copyright (C) 2003-2004, 2017-2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +#ifndef MARC_VIRTUAL_IMAGE_H +#define MARC_VIRTUAL_IMAGE_H + +#include "marc/SourceImage.h" +#include + + +namespace MaRC +{ + + /** + * @class VirtualImage VirtualImage.h + * + * @brief Base class for virtual source images. + * + * Data from virtual images are computed at run-time rather than + * retrieved from static sources such as images stored on a + * filesystem. + */ + class MARC_API VirtualImage : public SourceImage + { + public: + + /** + * @brief Constructor. + * + * @param[in] s Linear scaling coefficient applied to computed + * data. + * @param[in] o Linear offset value applied to all (scaled) + * computed data. + */ + VirtualImage(double s = 1, double o = 0); + + /// Destructor. + virtual ~VirtualImage() = default; + + /** + * @brief Retrieve data from virtual image. + * + * Retrieve data from virtual image and apply configured data + * transformations, if any. Raw physical data is + * computed/retrieved from the @c read_data_i() template + * method. + * + * @param[in] lat Planetocentric latitude in radians. + * @param[in] lon Longitude in radians. + * @param[out] data Data retrieved from image. + * + * @retval true Data retrieved + * @retval false No data retrieved. + * + * @note The retrieved data will be scaled and offset using + * the respective values passed to the @c VirtualImage + * constructor. This behavior differs from behavior + * documented in the @c SourceImage abstract base class + * where the data is expected to be physical data. The + * reason for this is historical. %MaRC virtual images, + * such as μ, μ0 and cos(φ), were + * originally embedded in %FITS files with potentially + * different kinds of physical data stored in an integer + * typed map "cube". To retain significant digits, + * floating point physical data values, such as the + * computed cosines mentioned earlier, were scaled and + * offset accordingly. Ideally, different physical data + * types shouldn't be mixed and matched in such a data + * cube, and should instead be stored in a cube + * containing matching physical data types within a + * map. Appropriate scale and offset values could then + * be applied to the data cube as a whole, rather than + * having to worry about applying a different scale and + * offset for each cube "plane". + * + * @see read_data_i() + */ + virtual bool read_data(double lat, + double lon, + double & data) const override; + + /** + * @name Linear Data Transformation + * + * These methods return the scale and offset values that + * should be used when linearly transforming data read from a + * @ c VirtualImage and plotted on a map to the true physical + * values. In particular, data should be transformed + * according to the following equation: + * + * @code + * physical_value = map_value * scale() + offset(); + * @endcode + * + * The default implementation returns values that causes no + * transformation to occur. + */ + //@{ + /** + * @brief Data scale. + * + * Linear scaling coefficient that should be applied to map + * data to transform that data to true physical data. + * + * @return Data scale. + */ + double scale() const { return 1 / this->scale_; } + + /** + * @brief Data offset + * Offset value that should be applied to all (scaled) + * computed data. This value corresponds to zero in the + * virtual image. + * + * @return Data offset. + */ + double offset() const { return this->scale() * -this->offset_; } + //@} + + private: + + /** + * @brief Compute physical data specific to a given virtual + * image. + * + * This template method is the core implementation of the + * @c read_data() method. + * + * @param[in] lat Planetocentric latitude in radians. + * @param[in] lon Longitude in radians. + * @param[out] data Physical data retrieved from image. + * + * @retval true Physical data retrieved + * @retval false No physical data retrieved. + * + * @see read_data() + */ + virtual bool read_data_i(double lat, + double lon, + double & data) const = 0; + + private: + + /** + * @brief Linear scaling coefficient applied to physical + * data. + * + * Linear scaling coefficient applied to physical data to + * allow data to fit in map array element of specific type + * with the most amount of significant digits. + * + * @note This is inverse of the scaling coefficient needed to + * retrieve the true physical value. + * + * @see @c VirtualImage::scale() + */ + double const scale_; + + /** + * @brief Offset value applied to scaled physical data. + * + * This offset is applied to scaled physical data to allow + * data fit in a map array element of specific type with the + * most amount of significant digits. + * + * @note This is the negative offset multiplied by the inverse + * of the of scaling value needed to retrieve the true + * physical value. + * + * @see @c VirtualImage::offset() + */ + double const offset_; + + }; + +} // End MaRC namespace + + +#endif /* MARC_VIRTUAL_IMAGE_H */ diff --git a/lib/marc/details/scale_and_offset.h b/lib/marc/details/scale_and_offset.h new file mode 100644 index 00000000..425d1eb5 --- /dev/null +++ b/lib/marc/details/scale_and_offset.h @@ -0,0 +1,235 @@ +// -*- C++ -*- +/** + * @file details/scale_and_offset.h + * + * Copyright (C) 2017-2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +#ifndef MARC_DETAILS_SCALE_AND_OFFSET_H +#define MARC_DETAILS_SCALE_AND_OFFSET_H + +#include +#include + + +namespace MaRC +{ + namespace details + { + /** + * @struct scale_and_offset details/scale_and_offset.h + * + * @brief Integer data scale and offset calculation functor. + * + * Determine the best scale and offset parameters applied to + * floating point data read from source images to retain as + * many significant digits as possible when storing that data + * in integer typed maps. + * + * @tparam T Destination data type. + * + * @see MaRC::scale_and_offset() + * + * @note This functor is not part of the public %MaRC library + * API. + */ + template + struct scale_and_offset + { + /** + * @brief Compute data scaling values. + * + * Given the source data range [@a min, @a max], determine + * the @a scale and @a offset values suitable for + * maximizing the number of significant digits retained + * when storing their floating point values in a + * destination of data type @a T. + * + * @param[in] min The minimum source value to be + * potentially stored in an integer of + * type @c T. + * @param[in] max The maximum source value to be + * potentially stored in an integer of + * type @c T. + * @param[out] scale Factor by which to multiply the + * source value to bring it into + * destination data type @c T range. + * This will always be a power of 10 + * for simplicity. + * @param[out] offset Value added to the source value to + * bring it into the destination data + * type @c T range. + * + * @retval true Suitable @a scale and @a offset values were + * found. + * @retval false Suitable @a scale and @a offset values were not + * found, such as when a complete loss of + * significant digits would occur when + * scaled and offset values are assigned to + * an integer due to trunctation (e.g. + * @a scale < 1). + * + * @see MaRC::scale_and_offset() for further details. + */ + bool operator()(double min, + double max, + double & scale, + double & offset) const + { + constexpr auto T_lowest = std::numeric_limits::lowest(); + constexpr auto T_max = std::numeric_limits::max(); + + static_assert( + T_lowest >= std::numeric_limits::lowest() / 2 + && T_max <= std::numeric_limits::max() / 2, + "Integer type is too large for " + "scale/offset calculation"); + + /* + Avoid integer overflow by performing a floating point + subtraction. No overflow will occur since we already + know: + T_max - T_lowest < std::numeric_limits::max() + */ + constexpr double type_range = + static_cast(T_max) - T_lowest; + + double const data_range = max - min; + + if (!std::isfinite(data_range) + || data_range < 0 + || data_range > type_range) { + // data_range is not a finite value + // (e.g. overflowed) or min > max or can't fit all + // data into desired type T + return false; + } + + int const exponent = + static_cast(std::numeric_limits::digits10) + - static_cast(std::log10(data_range)); + + scale = std::pow(10, exponent); + + if (min * scale < T_lowest) + offset = data_range / 2 * scale; + else if (max * scale > T_max) + offset = -data_range / 2 * scale; + else + offset = 0; + + return true; + } + }; + + /** + * @struct scale_and_offset details/scale_and_offset.h + + * @brief @c float typed data scale and offset calculation + * functor. + * + * Automatic source data scaling is not performed when mapping + * to floating point typed maps. This implementation is + * basically a no-op, and returns @a scale and @a offset + * values that result in the source data remaining unchanged. + * + * @see MaRC::scale_and_offset() + * + * @note This functor is not part of public %MaRC library + * API. + */ + template <> + struct scale_and_offset + { + /** + * @brief @c float destination data type specialization. + * + * No scaling is needed for floating point types. + * + * @param[out] scale This will always be 1. + * @param[out] offset This will always be 0. + * + * @return This specialization always returns @c true. + * + * @see MaRC::details::scale_and_offset + * @see MaRC::scale_and_offset() + */ + bool operator()(double /* min */, + double /* max */, + double & scale, + double & offset) const + { + // No auto-scaling for floating point map data. + scale = 1; + offset = 0; + + return true; + } + }; + + /** + * @struct scale_and_offset details/scale_and_offset.h + * + * @brief @c double typed data scale and offset calculation + * functor. + * + * Automatic source data scaling is not performed when mapping + * to floating point typed maps. This implementation is + * basically a no-op, and returns @a scale and @a offset + * values that result in the source data remaining unchanged. + * + * @see MaRC::scale_and_offset() + * + * @note This functor is not part of public %MaRC library + * API. + */ + template <> + struct scale_and_offset + { + /** + * @brief @c double destination data type specialization. + * + * No scaling is needed for floating point types. + * + * @param[out] scale This will always be 1. + * @param[out] offset This will always be 0. + * + * @return This specialization always returns @c true. + * + * @see MaRC::details::scale_and_offset + * @see MaRC::scale_and_offset() + */ + bool operator()(double /* min */, + double /* max */, + double & scale, + double & offset) const + { + // No auto-scaling for floating point map data. + scale = 1; + offset = 0; + + return true; + } + }; + } // details +} // End MaRC namespace + + +#endif /* MARC_DETAILS_SCALE_AND_OFFSET_H */ diff --git a/lib/marc/details/vector.h b/lib/marc/details/vector.h new file mode 100644 index 00000000..331c6127 --- /dev/null +++ b/lib/marc/details/vector.h @@ -0,0 +1,124 @@ +// -*- C++ -*- +/** + * @file details/vector.h + * + * %MaRC mathematical vector class implementation details. + * + * Copyright (C) 2004, 2017-2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +#ifndef MARC_DETAILS_VECTOR_H +#define MARC_DETAILS_VECTOR_H + +#include "marc/Mathematics.h" + + +namespace MaRC +{ + /** + * @namespace details + * + * @brief Internal %MaRC implementation details. + * + * Implementation details that are not part of the %MaRC public + * API. + */ + namespace details + { + /** + * @brief Obtain magnitude of a vector. + * + * This generalized implementation can return the magnitude of + * a vector with an arbitrary number of rows. + * + * @param[in] v Vector, represented as a simple array, for + * which the magnitude will be calculated. + * + * @return Magnitude of vector @a v. + */ + template + auto magnitude(T const (&v)[M]) + { + double const m = 0; + + /** + * @bug This implementation is subject to overflow or + * underflow. + */ + for (auto i = 0; i < M; ++i) + m += v[i] * v[i]; + + return std::sqrt(m); + } + + /** + * @brief Obtain magnitude of a vector with three rows. + * + * This implementation avoids overflow and underflow when + * calculating the magnitude of vectors with three rows. + * + * @param[in] v Vector, represented as an array, for which the + * magnitude will be calculated. + * + * @return Magnitude of vector @a v. + */ + template + constexpr auto magnitude(T const (&v)[3]) + { + return MaRC::hypot(v[0], v[1], v[2]); + } + + /** + * @brief Obtain magnitude of vector with two rows. + * + * This implementation avoids overflow and underflow when + * calculating the magnitude of vectors with two rows. + * + * @param[in] v Vector, represented as an array, for which the + * magnitude will be calculated. + * + * @return Magnitude of vector @a v. + */ + template + constexpr auto magnitude(T const (&v)[2]) + { + return std::hypot(v[0], v[1]); + } + + /** + * @brief Obtain magnitude of vector with one row. + * This implementation returns the magnitude of vector with + * one row. + * + * @param[in] v Vector, represented as an array, for which the + * magnitude will be calculated. + * + * @return Magnitude of vector @a v. + */ + template + constexpr auto magnitude(T const (&v)[1]) + { + return v[0]; + } + } // details +} // MaRC + + +#endif /* MARC_DETAILS_VECTOR_H */ diff --git a/lib/marc/optional.h b/lib/marc/optional.h new file mode 100644 index 00000000..3a2138cb --- /dev/null +++ b/lib/marc/optional.h @@ -0,0 +1,496 @@ +// -*- C++ -*- +/** + * @file optional.h + * + * Copyright (C) 2018 Ossama Othman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * @author Ossama Othman + * + * @deprecated This header will be removed in favor of the C++17 + * @ header once %MaRC requires C++17. + */ + +#ifndef MARC_OPTIONAL_H +#define MARC_OPTIONAL_H + +#if __cplusplus < 201703L +# include +# include +# include +#else +# include +#endif // __cplusplus < 201703L + + +namespace MaRC +{ +#if __cplusplus < 201703L + /** + * @struct nullopt_t optional.h + * + * @brief Null initialization type for @c optional. + * + * @deprecated This is an implementation of the C++17 + * @c std::nullopt_t type. It will be removed when + * %MaRC requires C++17. + */ + struct nullopt_t { + /// Constructor. + explicit constexpr nullopt_t(int) {} + }; + + /** + * @brief Constant used to null initialize an @c optional object. + */ + constexpr nullopt_t nullopt{0}; + + /** + * @class bad_optional_access optional.h + * + * @brief Exception thrown when an accessing a @c optional object + * doesn't contain a value. + * + * @deprecated This is an implementation of the C++17 + * @c std::bad_optional_access exception. It will be + * removed when %MaRC requires C++17. + * + * @see https://en.cppreference.com/w/cpp/utility/optional/bad_optional_access + */ + class bad_optional_access : public std::exception + { + public: + bad_optional_access() = default; + virtual ~bad_optional_access() = default; + + /// Return description of this exception. + virtual char const * what () const noexcept + { + return "bad optional access"; + } + }; + + /** + * @class optional optional.h + * + * @brief Contain an optional value. + * + * @note This class only implements a subset of the C++17 + * std::optional class template interface. In particular, + * it is missing several constructors, the @c emplace() + * method, the @c std::hash() specialization, etc. + * + * @deprecated This is an implementation of a subset of the C++17 + * @c std::optional class template. It will be + * removed when %MaRC requires C++17. + * + * @see https://en.cppreference.com/w/cpp/utility/optional + */ + template + class optional + { + public: + + /** + * @name Members Found in the C++17 std::optional Class + * + * These are members found in the C++17 @c std::optional + * class template, implemented for @c MaRC::optional. + */ + //@{ + using value_type = T; + + constexpr optional() = default; + constexpr optional(nullopt_t) noexcept : value_() {} + constexpr optional(optional const & other) = default; + constexpr optional(optional && other) = default; + constexpr optional(T v) : value_(v, true) {} + ~optional() = default; + optional & operator=(nullopt_t) noexcept + { + this->reset(); + return *this; + } + optional & operator=(optional const & other) = default; + optional & operator=(optional && other) = default; + + constexpr T const * operator->() const + { + return &this->value_.first; + } + + constexpr T * operator->() + { + return &this->value_.first; + } + + constexpr T const & operator*() const & + { + return this->value_.first; + } + + constexpr T & operator*() & + { + return this->value_.first; + } + + constexpr const T && operator*() const && + { + return this->value_.first; + } + + constexpr T && operator*() && + { + return this->value_.first; + } + + constexpr explicit operator bool() const noexcept + { + return this->value_.second; + } + + constexpr bool has_value() const noexcept + { + return this->value_.second; + } + + constexpr T & value() & + { + if (!this->has_value()) + throw bad_optional_access(); + + return this->value_.first; + } + + constexpr T const & value() const & + { + if (!this->has_value()) + throw bad_optional_access(); + + return this->value_.first; + } + + constexpr T && value() && + { + if (!this->has_value()) + throw bad_optional_access(); + + return this->value_.first; + } + + constexpr T const && value() const && + { + if (!this->has_value()) + throw bad_optional_access(); + + return this->value_.first; + } + + template + constexpr T value_or(U && default_value) const & + { + return + this->has_value() + ? this->value_.first + : static_cast(std::forward(default_value)); + } + + template + constexpr T value_or(U && default_value) && + { + return + this->has_value() + ? std::move(this->value_.first) + : static_cast(std::forward(default_value)); + } + + void swap(optional & other) noexcept( + std::is_nothrow_move_constructible::value + /* && std::is_nothrow_swappable::value */) + { + this->value_.swap(other.value_); + } + + void reset() noexcept + { + this->value_ = decltype(this->value_)(); + } + //@} + + private: + + /** + * @brief Member that tracks the existence of an %optional + * value, and the value itself. + */ + std::pair value_; + + }; + + /** + * @brief Create an @c optional object. + * + * @param[in,out] value Value to be stored in the created + * @c optional object. + * + * @return @c optional object containing the provided @a value. + * + * @relates MaRC::optional + */ + template + constexpr optional> make_optional(T && value) + { + return optional>(std::forward(value)); + } + + /** + * @name Comparison Operators + * + * @relates MaRC::optional + */ + //@{ + template + constexpr bool operator==(optional const & lhs, + optional const & rhs) + { + return (lhs && rhs && *lhs == *rhs) + || (!lhs && !rhs); + } + + template + constexpr bool operator!=(optional const & lhs, + optional const & rhs) + { + return !(lhs == rhs); + } + + template + constexpr bool operator<(optional const & lhs, + optional const & rhs) + { + return !lhs || (rhs && *lhs < *rhs); + } + + template + constexpr bool operator<=(optional const & lhs, + optional const & rhs) + { + return !lhs || (rhs && *lhs <= *rhs); + } + + template + constexpr bool operator>(optional const & lhs, + optional const & rhs) + { + return rhs < lhs; + } + + template + constexpr bool operator>=(optional const & lhs, + optional const & rhs) + { + return rhs <= lhs; + } + + // ----------------- + + template< class T > + constexpr bool operator==(optional const & opt, nullopt_t) noexcept + { + return !opt; + } + + template< class T > + constexpr bool operator==(nullopt_t, optional const & opt) noexcept + { + return !opt; + } + + template< class T > + constexpr bool operator!=(optional const & opt, nullopt_t) noexcept + { + return bool(opt); + } + + template< class T > + constexpr bool operator!=(nullopt_t, + optional const & opt) noexcept + { + return bool(opt); + } + + template< class T > + constexpr bool operator<(optional const &, nullopt_t) noexcept + { + return false; + } + + template< class T > + constexpr bool operator<(nullopt_t, optional const & opt) noexcept + { + return bool(opt); + } + + template< class T > + constexpr bool operator<=(optional const & opt, nullopt_t) noexcept + { + return !opt; + } + + template< class T > + constexpr bool operator<=(nullopt_t, optional const &) noexcept + { + return true; + } + + template< class T > + constexpr bool operator>(optional const & opt, nullopt_t) noexcept + { + return bool(opt); + } + + template< class T > + constexpr bool operator>(nullopt_t, optional const &) noexcept + { + return false; + } + + template< class T > + constexpr bool operator>=(optional const &, nullopt_t) noexcept + { + return true; + } + + template< class T > + constexpr bool operator>=(nullopt_t, + optional const & opt) noexcept + { + return !opt; + } + + // ----------------- + + template + constexpr bool operator==(optional const & opt, + U const & value) + { + return opt ? *opt == value : false; + } + + template + constexpr bool operator==(T const & value, + optional const & opt) + { + return opt ? value == *opt : false; + } + + template + constexpr bool operator!=(optional const & opt, + U const & value) + { + return opt ? *opt != value : true; + } + + template + constexpr bool operator!=(T const & value, + optional const & opt) + { + return opt ? value != *opt : true; + } + + template + constexpr bool operator<(optional const & opt, + U const & value) + { + return opt ? *opt < value : true; + } + + template + constexpr bool operator<(T const & value, + optional const & opt) + { + return opt ? value < *opt : false; + } + + template + constexpr bool operator<=(optional const & opt, + U const & value) + { + return opt ? *opt <= value : true; + } + + template + constexpr bool operator<=(T const & value, + optional const & opt) + { + return opt ? value <= *opt : false; + } + + template + constexpr bool operator>(optional const & opt, + U const & value) + { + return opt ? *opt > value : false; + } + + template + constexpr bool operator>(T const & value, + optional const & opt) + { + return opt ? value > *opt : true; + } + + template + constexpr bool operator>=(optional const & opt, + U const & value) + { + return opt ? *opt >= value : false; + } + + template + constexpr bool operator>=(T const & value, + optional const & opt) + { + return opt ? value >= *opt : true; + } + //@} +#else + using std::nullopt_t; + using std::nullopt; + using std::bad_optional_access; + using std::optional; + using std::make_optional; +#endif // __cplusplus >= 201703L +} + +#if __cplusplus < 201703L +namespace std +{ + /** + * @brief Swap contents of MaRC::optional objects. + * + * @relates MaRC::optional + */ + template + void swap(MaRC::optional & lhs, MaRC::optional & rhs) noexcept( + noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } +} +#endif // __cplusplus < 201703L + +#endif // MARC_OPTIONAL_H diff --git a/lib/marc/plot_info.h b/lib/marc/plot_info.h new file mode 100644 index 00000000..6790f5c9 --- /dev/null +++ b/lib/marc/plot_info.h @@ -0,0 +1,238 @@ +// -*- C++ -*- +/** + * @file plot_info.h + * + * Copyright (C) 2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +#ifndef MARC_PLOT_INFO_H +#define MARC_PLOT_INFO_H + +#include +#include +#include + +#include +#include + +namespace MaRC +{ + class SourceImage; + + /** + * @class plot_info plot_info.h + * + * @brief Map plotting information. + * + * Information that will be used when a plotting a map is + * enscapsulated in this class. + */ + class MARC_API plot_info + { + public: + + /// Convenience alias for the progress notifier type. + using notifier_type = Progress::Notifier; + + /// Convenience alias for the blank integer type. + using blank_type = MaRC::optional; + + /** + * @brief Constructor used when no blank value is provided. + * + * By default, %MaRC will use @c 0 as the blank value for + * integer typed maps, and always use %c NaN for floating + * point typed maps. + * + * @param[in] source @c SourceImage object containing the + * data to be mapped. + * @param[in] minimum Minimum allowed physical data value on + * map, i.e. all data greater than or + * equal to @a minimum. + * @param[in] maximum Maximum allowed physical data value on + * map, i.e. all data less than or equal + * to @a maximum. + */ + plot_info(SourceImage const & source, + double minimum, + double maximum) + : source_(source) + , minimum_(validate_extremum(minimum)) + , maximum_(validate_extremum(maximum)) + , blank_() + , notifier_() + { + } + + /** + * @brief Constructor for integer blank types. + * + * Constructor used when supplying an integer typed @a blank + * value. + * + * @param[in] source @c SourceImage object containing the + * data to be mapped. + * @param[in] minimum Minimum allowed physical data value on + * map, i.e. all data greater than or + * equal to @a minimum. + * @param[in] maximum Maximum allowed physical data value on + * map, i.e. all data less than or equal + * to @a maximum. + * @param[in] blank Blank map array value for integer typed + * maps. The blank map array value + * corresponds to undefined "blank" + * physical values. + */ + template + plot_info(SourceImage const & source, + double minimum, + double maximum, + T blank) + : source_(source) + , minimum_(validate_extremum(minimum)) + , maximum_(validate_extremum(maximum)) + , blank_(blank) + , notifier_() + { + } + + /** + * @brief Constructor for floating point blank types. + * + * Constructor used when supplying a floating point typed + * @a blank value. In this case, the floating point value is + * actually ignored since the @c NaN constant is expected to + * be used as the blank value in %MaRC generated floating + * point typed map projections. + * + * This constructor exists to prevent implicit conversions + * from a floating point blank value to the integer based + * @c blank_type used by this class. For example, this + * constructor prevents attempts to assign + * std::numeric_limits::lowest() as the blank + * value since that would result in an overflow. + * + * @param[in] source @c SourceImage object containing the + * data to be mapped. + * @param[in] minimum Minimum allowed physical data value on + * map, i.e. all data greater than or + * equal to @a minimum. + * @param[in] maximum Maximum allowed physical data value on + * map, i.e. all data less than or equal + * to @a maximum. + */ + plot_info(SourceImage const & source, + double minimum, + double maximum, + double /* unused */) + : plot_info(source, minimum, maximum) + { + } + + ~plot_info() = default; + plot_info(plot_info const &) = delete; + void operator=(plot_info const &) = delete; + + /// Get data to be mapped. + SourceImage const & source() const { return this->source_; } + + /// Set minimum allowed value on map. + void minimum(double m) { this->minimum_ = validate_extremum(m); } + + /// Get minimum allowed physical data value on map. + double minimum() const { return this->minimum_; } + + /// Set maximum allowed physical data value on map. + void maximum(double m) { this->maximum_ = validate_extremum(m); } + + /// Get maximum allowed physical data value on map. + double maximum() const { return this->maximum_; } + + /// Get blank map array value. + blank_type const & blank() const + { + return this->blank_; + } + + /** + * @brief Get map progress notifier. + * + * Use this notifier to subscribe observers for map progress + * notifications. + * + * @see Notifier + */ + notifier_type & notifier() const { return this->notifier_; } + + private: + + /** + * @brief Verify extremum (minimum or maxium) is valid. + * + * Verify that the given extremum @a value is valid, i.e. not + * @c NaN. + * + * @param[in] value Physical data extremum to be validated. + * + * @return @a value if it is valid. + * + * @throw std::invalid_argument @a value is @c NaN. + */ + static double validate_extremum(double value) + { + if (std::isnan(value)) + throw std::invalid_argument( + "plot_info minimum/maximum should not be NaN."); + + return value; + } + + private: + + /// @c SourceImage object containing the data to be mapped. + SourceImage const & source_; + + /** + * @brief Minimum allowed physical data value on the map, + * i.e. data >= @c minimum_. + */ + double minimum_; + + /** + * @brief Maximum allowed physical data value on the map, + * i.e. data <= @c maximum_. + */ + double maximum_; + + /** + * @brief Value of pixels with undefined physical value. + * + * @note This value is only valid for integer typed maps. + */ + blank_type const blank_; + + /// Map progress notifier. + mutable notifier_type notifier_; + + }; + +} // MaRC + +#endif // MARC_PLOT_INFO_H diff --git a/lib/MaRC/root_find.cpp b/lib/marc/root_find.cpp similarity index 98% rename from lib/MaRC/root_find.cpp rename to lib/marc/root_find.cpp index f8bc3ca5..7316c783 100644 --- a/lib/MaRC/root_find.cpp +++ b/lib/marc/root_find.cpp @@ -1,7 +1,7 @@ /** * @file root_find.cpp * - * MaRC root finding related functions + * %MaRC root finding related functions * * Copyright (C) 2004, 2017-2018 Ossama Othman * @@ -25,7 +25,10 @@ #include "root_find.h" #include "Mathematics.h" -// #include "Log.h" + +#ifndef NDEBUG +// # include "Log.h" +#endif #include #include diff --git a/lib/MaRC/root_find.h b/lib/marc/root_find.h similarity index 98% rename from lib/MaRC/root_find.h rename to lib/marc/root_find.h index f1e425db..cc9e1e0a 100644 --- a/lib/MaRC/root_find.h +++ b/lib/marc/root_find.h @@ -2,7 +2,7 @@ /** * @file root_find.h * - * MaRC root finding related functions + * %MaRC root finding related functions * * Copyright (C) 2004, 2017-2018 Ossama Othman * @@ -27,7 +27,7 @@ #ifndef MARC_ROOT_FIND_H #define MARC_ROOT_FIND_H -#include +#include #include diff --git a/lib/marc/scale_and_offset.h b/lib/marc/scale_and_offset.h new file mode 100644 index 00000000..78d610ff --- /dev/null +++ b/lib/marc/scale_and_offset.h @@ -0,0 +1,137 @@ +// -*- C++ -*- +/** + * @file marc/scale_and_offset.h + * + * Copyright (C) 2017-2018 Ossama Othman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @author Ossama Othman + */ + +#ifndef MARC_SCALE_AND_OFFSET_H +#define MARC_SCALE_AND_OFFSET_H + +#include + + +namespace MaRC +{ + + /** + * @brief Determine suitable data scale and offset values. + * + * Determine the best scale and offset parameters applied to + * floating point data read from source images to retain as many + * significant digits as possible when storing that data in + * integer typed maps. + * + * Some source images, e.g. @c MaRC::VirtualImage subclasses, only + * provide floating point numbers. That is a problem when storing + * those numbers in integer typed maps since significant digits + * after the decimal point could be truncated when casting from + * floating point to integer. To reduce the loss of significant + * digits in such cases, the data should be scaled upward and + * potentially offset from their original values so that more + * significant digits end up to the left of the decimal point + * prior to assignment to integer typed map array elements. + * + * For example, cosine values to be stored in a 16 bit signed + * integer map could be scaled by 10000 with a zero offset to + * increase the number of significant digits in the map data from + * one to four, e.g. 0.1234567 becomes 1234.567, which ends up + * being stored as 1234 in a 16 bit signed integer map. A scale + * factor of 10000 in this case is suitable since the scaled data + * range, -10000 to 10000, never exceeds the 16 bit signed integer + * data range, i.e -32768 to 32767. The chosen scale order of + * magnitude is the largest it can be without causing transformed + * data to exceed the map data range. + * + * To reduce potential confusion about what the data actually is, + * only power of 10 scale factors (i.e. 1, 10, 100, etc) are + * chosen. Unless the data minimum (@a min) and maximum (@a max) + * are not symmetrical and/or the map data type is unsigned, the + * offset value will generally be zero. + * + * The physical data should be transformed according to the + * following equation prior to mapping: + * + * @code + * map_data = scale * physical_data + offset + * @endcode + * + * Retrieving the original physical data from the map would then + * require the following equation: + * + * @code + * physical_data = (map_data - offset) / scale + * @endcode + * + * @note The @a scale and @a offset will always be 1 and 0, + * respectively, if the map data type is a floating point + * type, i.e. @c float or @c double. + * + * @attention This function only generates @a scale and @a offset + * values that allow data to fit within the map type + * @a T data range without decreasing the order of + * magnitude of the data, Otherwise a complete loss of + * significant digits would occur since they'd all be + * to the right of the decimal point, and ultimately + * truncated when assigned to an integer. In + * particular, the scale value will always be greater + * than or equal to one if this function completes + * successfully. + * + * @tparam T Destination data type. + * @param[in] min The lowest physical value to be plotted on a + * map. For example, this would be -1 for + * source images that generate cosines. + * @param[in] max The highest physical value to be plotted on + * a map. For example, this would be 1 for + * source images that generate cosines. + * @param[out] scale Linear scaling value by which physical data + * should be multiplied to maximize the number + * of significant digits prior to storing data + * in an integer typed map. This will be 1 for + * floating point typed maps. + * @param[out] offset Offset value to be added to data after the + * scaling factor has been applied to force + * that data to fit within the integer typed + * map data range. This will be 0 for floating + * point typed maps. + * + * @retval true Suitable @a scale and @a offset values were + * found. + * @retval false Suitable @a scale and @a offset values were not + * found. This can occur if it isn't possible to + * scale data without complete loss of significant + * digits when assigned to an integer due to + * trunctation, such as when a scale factor less + * than 1 would be required. + */ + template + bool scale_and_offset(double min, + double max, + double & scale, + double & offset) + { + return details::scale_and_offset()(min, max, scale, offset); + } + +} + + +#endif // MARC_SCALE_AND_OFFSET_H diff --git a/lib/MaRC/utility.h b/lib/marc/utility.h similarity index 69% rename from lib/MaRC/utility.h rename to lib/marc/utility.h index 38a4e9b9..8c10ef30 100644 --- a/lib/MaRC/utility.h +++ b/lib/marc/utility.h @@ -2,7 +2,7 @@ /** * @file utility.h * - * MaRC utility functions. + * %MaRC utility functions. * * Copyright (C) 2017, 2018 Ossama Othman * @@ -27,13 +27,43 @@ #ifndef MARC_UTILITY_H #define MARC_UTILITY_H -#include +#include #include #include namespace MaRC { +#if __cplusplus < 201703L + /** + * @brief Get the size of a container. + * + * @deprecated This is an implementation of the C++17 + * @c std::size() function. It will be removed when + * %MaRC requires C++17. + */ + template + constexpr auto size(C const & c) -> decltype(c.size()) + { + return c.size(); + } + + /** + * @brief Get the length of an array. + * + * @deprecated This is an implementation of the C++17 + * @c std::size() function. It will be removed when + * %MaRC requires C++17. + */ + template + constexpr std::size_t size(T const (& /* array */)[N]) noexcept + { + return N; + } +#else + using std::size; +#endif // __cplusplus < 201703L + /** * @brief Invert image samples (columns). * @@ -41,7 +71,8 @@ namespace MaRC * reflected from left to right about the center column. * * @param[in,out] image Image to be inverted from left to - * right. + * right. This should be an array or + * container. * @param[in] samples Number of columns in the @a image. * @param[in] lines Number of rows in the @a image. * @@ -50,15 +81,15 @@ namespace MaRC */ template void - invert_samples(std::vector & image, + invert_samples(T & image, std::size_t samples, std::size_t lines) { - if (image.size() != samples * lines) + if (MaRC::size(image) != samples * lines) throw std::invalid_argument("Image size does not match " "number of samples and lines."); - auto begin = image.begin(); + auto begin = std::begin(image); for (std::size_t line = 0; line < lines; ++line) { auto const end = begin + samples; std::reverse(begin, end); @@ -73,7 +104,8 @@ namespace MaRC * from top to bottom about the center row. * * @param[in,out] image Image to be inverted from top to - * bottom. + * bottom. This should be an array or + * container. * @param[in] samples Number of columns in the @a image. * @param[in] lines Number of rows in the @a image. * @@ -82,11 +114,11 @@ namespace MaRC */ template void - invert_lines(std::vector & image, + invert_lines(T & image, std::size_t samples, std::size_t lines) { - if (image.size() != samples * lines) + if (MaRC::size(image) != samples * lines) throw std::invalid_argument("Image size does not match " "number of samples and lines."); @@ -94,12 +126,12 @@ namespace MaRC for (std::size_t line = 0; line < middle; ++line) { // Line from one end. - auto const top_begin = image.begin() + line * samples; + auto const top_begin = std::begin(image) + line * samples; auto const top_end = top_begin + samples; // Line from the other end. std::size_t const offset = (lines - line - 1) * samples; - auto const bottom_begin = image.begin() + offset; + auto const bottom_begin = std::begin(image) + offset; // Swap the lines. std::swap_ranges(top_begin, top_end, bottom_begin); diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4 index d36bcdff..7bc77108 100644 --- a/m4/ax_check_enable_debug.m4 +++ b/m4/ax_check_enable_debug.m4 @@ -42,7 +42,7 @@ # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. -#serial 8 +#serial 9 AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ AC_BEFORE([$0],[AC_PROG_CC])dnl @@ -118,7 +118,7 @@ AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ dnl Define various variables if debugging is disabled. dnl assert.h is a NOP if NDEBUG is defined, so define it by default. AS_IF([test "x$enable_debug" = "xyes"], - [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], - [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) + [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,[1],[Define if debugging is enabled])])], + [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,[1],[Define if debugging is disabled])])]) ax_enable_debug=$enable_debug ]) diff --git a/m4/ax_code_coverage.m4 b/m4/ax_code_coverage.m4 index 2b2071d9..3d36924b 100644 --- a/m4/ax_code_coverage.m4 +++ b/m4/ax_code_coverage.m4 @@ -40,7 +40,7 @@ # my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ... # # clean-local: code-coverage-clean -# dist-clean-local: code-coverage-dist-clean +# distclean-local: code-coverage-dist-clean # # This results in a "check-code-coverage" rule being added to any # Makefile.am which do "include $(top_srcdir)/aminclude_static.am" @@ -49,7 +49,7 @@ # module's test suite (`make check`) and build a code coverage report # detailing the code which was touched, then print the URI for the report. # -# This code was derived from Makefile.decl in GLib, originally licenced +# This code was derived from Makefile.decl in GLib, originally licensed # under LGPLv2.1+. # # LICENSE @@ -74,7 +74,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . -#serial 30 +#serial 32 m4_define(_AX_CODE_COVERAGE_RULES,[ AX_ADD_AM_MACRO_STATIC([ diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 5032bba8..9e9eaeda 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -33,19 +33,18 @@ # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler -# Copyright (c) 2016 Krzesimir Nowak +# Copyright (c) 2016, 2018 Krzesimir Nowak # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 7 +#serial 10 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). -AX_REQUIRE_DEFINED([AC_MSG_WARN]) AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], @@ -61,14 +60,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then @@ -139,7 +130,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) - m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) ]) @@ -587,20 +577,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ #error "This is not a C++ compiler" -#elif __cplusplus <= 201402L +#elif __cplusplus < 201703L #error "This is not a C++17 compiler" #else -#if defined(__clang__) - #define REALLY_CLANG -#else - #if defined(__GNUC__) - #define REALLY_GCC - #endif -#endif - #include #include #include @@ -608,16 +590,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ namespace cxx17 { -#if !defined(REALLY_CLANG) namespace test_constexpr_lambdas { - // TODO: test it with clang++ from git - constexpr int foo = [](){return 42;}(); } -#endif // !defined(REALLY_CLANG) namespace test::nested_namespace::definitions { @@ -852,12 +830,9 @@ namespace cxx17 } -#if !defined(REALLY_CLANG) namespace test_template_argument_deduction_for_class_templates { - // TODO: test it with clang++ from git - template struct pair { @@ -876,7 +851,6 @@ namespace cxx17 } } -#endif // !defined(REALLY_CLANG) namespace test_non_type_auto_template_parameters { @@ -890,12 +864,9 @@ namespace cxx17 } -#if !defined(REALLY_CLANG) namespace test_structured_bindings { - // TODO: test it with clang++ from git - int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; @@ -927,14 +898,10 @@ namespace cxx17 const auto [ x3, y3 ] = f3(); } -#endif // !defined(REALLY_CLANG) -#if !defined(REALLY_CLANG) namespace test_exception_spec_type_system { - // TODO: test it with clang++ from git - struct Good {}; struct Bad {}; @@ -952,7 +919,6 @@ namespace cxx17 static_assert (std::is_same_v); } -#endif // !defined(REALLY_CLANG) namespace test_inline_variables { @@ -977,6 +943,6 @@ namespace cxx17 } // namespace cxx17 -#endif // __cplusplus <= 201402L +#endif // __cplusplus < 201703L ]]) diff --git a/m4/ax_prog_doxygen.m4 b/m4/ax_prog_doxygen.m4 index a371f7fd..ed1dc83b 100644 --- a/m4/ax_prog_doxygen.m4 +++ b/m4/ax_prog_doxygen.m4 @@ -97,7 +97,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 24 ## ----------## ## Defaults. ## @@ -164,7 +164,7 @@ AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) AC_DEFUN([DX_CHECK_DEPEND], [ test "$DX_FLAG_$1" = "$2" \ || AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, - requires, contradicts) doxygen-DX_CURRENT_FEATURE]) + requires, contradicts) doxygen-$1]) ]) # DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) diff --git a/m4/marc_code_coverage.m4 b/m4/marc_code_coverage.m4 new file mode 100644 index 00000000..2017b58c --- /dev/null +++ b/m4/marc_code_coverage.m4 @@ -0,0 +1,39 @@ +# Copyright (C) 2018 Ossama Othman +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#serial 1 + +# MARC_CODE_COVERAGE +# +# Add support for gcov/lcov based code coverage instrumentation and +# result generation. +AC_DEFUN([MARC_CODE_COVERAGE],[ + AC_REQUIRE([AX_CODE_COVERAGE]) + + # The AX_CODE_COVERAGE macro changed how it should be used. + # Previously, users had to add @CODE_COVERAGE_RULES@ to each + # Makefile.am file that listed code to be instrumented for code + # coverage. However, recent versions of that macro changed that to + # instead require users to add: + # include $(top_srcdir)/aminclude_static.am + # to their Makefile.am files. Work around that break in backward + # compatibility by explicitly adding the @CODE_COVERAGE_RULES@ to + # the `aminclude_static.am' file, and clearing out that substitution + # variable if it exists. It will only exist if the older + # AX_CODE_COVERAGE macro is in use. Otherwise it becomes a no-op. + AX_ADD_AM_MACRO_STATIC([@CODE_COVERAGE_RULES@]) + AC_CONFIG_COMMANDS_PRE([AC_SUBST([CODE_COVERAGE_RULES])]) +]) diff --git a/marc.dox b/marc.dox index ba08c0dc..7a646cc1 100644 --- a/marc.dox +++ b/marc.dox @@ -1,5 +1,5 @@ /** - * @mainpage MaRC - Map Reprojections and Conversions + * @mainpage %MaRC - Map Reprojections and Conversions * * * @section marc_main_sec marc diff --git a/opt/fmt-5.2.1/LICENSE.rst b/opt/fmt-5.2.1/LICENSE.rst new file mode 100644 index 00000000..eb6be650 --- /dev/null +++ b/opt/fmt-5.2.1/LICENSE.rst @@ -0,0 +1,23 @@ +Copyright (c) 2012 - 2016, Victor Zverovich + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/opt/fmt-5.2.1/include/fmt/color.h b/opt/fmt-5.2.1/include/fmt/color.h new file mode 100644 index 00000000..4973976a --- /dev/null +++ b/opt/fmt-5.2.1/include/fmt/color.h @@ -0,0 +1,278 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +#ifdef FMT_DEPRECATED_COLORS + +// color and (v)print_colored are deprecated. +enum color { black, red, green, yellow, blue, magenta, cyan, white }; +FMT_API void vprint_colored(color c, string_view format, format_args args); +FMT_API void vprint_colored(color c, wstring_view format, wformat_args args); +template +inline void print_colored(color c, string_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args(args...)); +} +template +inline void print_colored(color c, wstring_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args(args...)); +} + +inline void vprint_colored(color c, string_view format, format_args args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast('0' + c); + std::fputs(escape, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +inline void vprint_colored(color c, wstring_view format, wformat_args args) { + wchar_t escape[] = L"\x1b[30m"; + escape[3] = static_cast('0' + c); + std::fputws(escape, stdout); + vprint(format, args); + std::fputws(internal::data::WRESET_COLOR, stdout); +} + +#else + +// Experimental color support. +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32, // rgb(154,205,50) +}; // enum class color + +// rgb is a struct for red, green and blue colors. +// We use rgb as name because some editors will show it as color direct in the +// editor. +struct rgb { + FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) + : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR_DECL rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} + FMT_CONSTEXPR_DECL rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +void vprint_rgb(rgb fd, string_view format, format_args args); +void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args); + +/** + Formats a string and prints it to stdout using ANSI escape sequences to + specify foreground color 'fd'. + Example: + fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +inline void print(rgb fd, string_view format_str, const Args & ... args) { + vprint_rgb(fd, format_str, make_format_args(args...)); +} + +/** + Formats a string and prints it to stdout using ANSI escape sequences to + specify foreground color 'fd' and background color 'bg'. + Example: + fmt::print(fmt::color::red, fmt::color::black, + "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +inline void print(rgb fd, rgb bg, string_view format_str, + const Args & ... args) { + vprint_rgb(fd, bg, format_str, make_format_args(args...)); +} +namespace internal { +FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) { + out[offset + 0] = static_cast('0' + c / 100); + out[offset + 1] = static_cast('0' + c / 10 % 10); + out[offset + 2] = static_cast('0' + c % 10); +} +} // namespace internal + +inline void vprint_rgb(rgb fd, string_view format, format_args args) { + char escape_fd[] = "\x1b[38;2;000;000;000m"; + internal::to_esc(fd.r, escape_fd, 7); + internal::to_esc(fd.g, escape_fd, 11); + internal::to_esc(fd.b, escape_fd, 15); + + std::fputs(escape_fd, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) { + char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color + char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color + internal::to_esc(fd.r, escape_fd, 7); + internal::to_esc(fd.g, escape_fd, 11); + internal::to_esc(fd.b, escape_fd, 15); + + internal::to_esc(bg.r, escape_bg, 7); + internal::to_esc(bg.g, escape_bg, 11); + internal::to_esc(bg.b, escape_bg, 15); + + std::fputs(escape_fd, stdout); + std::fputs(escape_bg, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +#endif + +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/opt/fmt-5.2.1/include/fmt/core.h b/opt/fmt-5.2.1/include/fmt/core.h new file mode 100644 index 00000000..5912afef --- /dev/null +++ b/opt/fmt-5.2.1/include/fmt/core.h @@ -0,0 +1,1502 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include +#include // std::FILE +#include +#include +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 50201 + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && !defined(__INTELLISENSE__) && \ + (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION +#else +# define FMT_HAS_GXX_CXX11 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR inline +# define FMT_CONSTEXPR_DECL +#endif + +#ifndef FMT_USE_CONSTEXPR11 +# define FMT_USE_CONSTEXPR11 \ + (FMT_MSC_VER >= 1900 || FMT_GCC_VERSION >= 406 || FMT_USE_CONSTEXPR) +#endif +#if FMT_USE_CONSTEXPR11 +# define FMT_CONSTEXPR11 constexpr +#else +# define FMT_CONSTEXPR11 +#endif + +#ifndef FMT_OVERRIDE +# if FMT_HAS_FEATURE(cxx_override) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +#if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_MSC_VER >= 1800 +# define FMT_EXPLICIT explicit +#else +# define FMT_EXPLICIT +#endif + +#ifndef FMT_NULL +# if FMT_HAS_FEATURE(cxx_nullptr) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 +# define FMT_NULL nullptr +# define FMT_USE_NULLPTR 1 +# else +# define FMT_NULL NULL +# endif +#endif + +#ifndef FMT_USE_NULLPTR +# define FMT_USE_NULLPTR 0 +#endif + +#if FMT_HAS_CPP_ATTRIBUTE(noreturn) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +// Check if exceptions are disabled. +#if defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +#elif FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#ifndef FMT_EXCEPTIONS +# define FMT_EXCEPTIONS 1 +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +// This is needed because GCC still uses throw() in its headers when exceptions +// are disabled. +#if FMT_GCC_VERSION +# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT +#else +# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ + FMT_MSC_VER >= 1900 +# define FMT_INLINE_NAMESPACE inline namespace +# define FMT_END_NAMESPACE }} +# else +# define FMT_INLINE_NAMESPACE namespace +# define FMT_END_NAMESPACE } using namespace v5; } +# endif +# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 { +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_ASSERT +# define FMT_ASSERT(condition, message) assert((condition) && message) +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE() && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include +# define FMT_USE_STD_STRING_VIEW +#elif (FMT_HAS_INCLUDE() && \ + __cplusplus >= 201402L) +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +// std::result_of is defined in in gcc 4.4. +#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404 +# include +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An implementation of declval for pre-C++11 compilers such as gcc 4. +template +typename std::add_rvalue_reference::type declval() FMT_NOEXCEPT; + +template +struct result_of; + +template +struct result_of { + // A workaround for gcc 4.4 that doesn't allow F to be a reference. + typedef typename std::result_of< + typename std::remove_reference::type(Args...)>::type type; +}; + +// Casts nonnegative integer to unsigned. +template +FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast::type>(value); +} + +// A constexpr std::char_traits::length replacement for pre-C++17. +template +FMT_CONSTEXPR size_t length(const Char *s) { + const Char *start = s; + while (*s) ++s; + return s - start; +} +#if FMT_GCC_VERSION +FMT_CONSTEXPR size_t length(const char *s) { return std::strlen(s); } +#endif +} // namespace internal + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ +template +class basic_string_view { + private: + const Char *data_; + size_t size_; + + public: + typedef Char char_type; + typedef const Char *iterator; + + // Standard basic_string_view type. +#if defined(FMT_USE_STD_STRING_VIEW) + typedef std::basic_string_view type; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) + typedef std::experimental::basic_string_view type; +#else + struct type { + const char *data() const { return FMT_NULL; } + size_t size() const { return 0; } + }; +#endif + + FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT + : data_(s), size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR basic_string_view(const Char *s) + : data_(s), size_(internal::length(s)) {} + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string &s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} + + FMT_CONSTEXPR basic_string_view(type s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} + + /** Returns a pointer to the string data. */ + FMT_CONSTEXPR const Char *data() const { return data_; } + + /** Returns the string size. */ + FMT_CONSTEXPR size_t size() const { return size_; } + + FMT_CONSTEXPR iterator begin() const { return data_; } + FMT_CONSTEXPR iterator end() const { return data_ + size_; } + + FMT_CONSTEXPR void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + int compare(basic_string_view other) const { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + friend bool operator==(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) >= 0; + } +}; + +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; + +template +class basic_format_arg; + +template +class basic_format_args; + +template +struct no_formatter_error : std::false_type {}; + +// A formatter for objects of type T. +template +struct formatter { + static_assert(no_formatter_error::value, + "don't know how to format the type, include fmt/ostream.h if it provides " + "an operator<< that should be used"); + + // The following functions are not defined intentionally. + template + typename ParseContext::iterator parse(ParseContext &); + template + auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()); +}; + +template +struct convert_to_int { + enum { + value = !std::is_arithmetic::value && std::is_convertible::value + }; +}; + +namespace internal { + +/** A contiguous memory buffer with an optional growing ability. */ +template +class basic_buffer { + private: + basic_buffer(const basic_buffer &) = delete; + void operator=(const basic_buffer &) = delete; + + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + basic_buffer(std::size_t sz) FMT_NOEXCEPT: size_(sz), capacity_(sz) {} + + basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0) + FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {} + + /** Sets the buffer data and capacity. */ + void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(std::size_t capacity) = 0; + + public: + typedef T value_type; + typedef const T &const_reference; + + virtual ~basic_buffer() {} + + T *begin() FMT_NOEXCEPT { return ptr_; } + T *end() FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + std::size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T *data() FMT_NOEXCEPT { return ptr_; } + + /** Returns a pointer to the buffer data. */ + const T *data() const FMT_NOEXCEPT { return ptr_; } + + /** + Resizes the buffer. If T is a POD type new elements may not be initialized. + */ + void resize(std::size_t new_size) { + reserve(new_size); + size_ = new_size; + } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + /** Reserves space to store at least *capacity* elements. */ + void reserve(std::size_t new_capacity) { + if (new_capacity > capacity_) + grow(new_capacity); + } + + void push_back(const T &value) { + reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template + void append(const U *begin, const U *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +typedef basic_buffer buffer; +typedef basic_buffer wbuffer; + +// A container-backed buffer. +template +class container_buffer : public basic_buffer { + private: + Container &container_; + + protected: + void grow(std::size_t capacity) FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit container_buffer(Container &c) + : basic_buffer(c.size()), container_(c) {} +}; + +struct error_handler { + FMT_CONSTEXPR error_handler() {} + FMT_CONSTEXPR error_handler(const error_handler &) {} + + // This function is intentionally not constexpr to give a compile-time error. + FMT_API void on_error(const char *message); +}; + +// Formatting of wide characters and strings into a narrow output is disallowed: +// fmt::format("{}", L"test"); // error +// To fix this, use a wide format string: +// fmt::format(L"{}", L"test"); +template +inline void require_wchar() { + static_assert( + std::is_same::value, + "formatting of wide characters into a narrow output is disallowed"); +} + +template +struct named_arg_base; + +template +struct named_arg; + +template +struct is_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +enum type { + none_type, named_arg_type, + // Integer types should go first, + int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, + last_integer_type = char_type, + // followed by floating-point types. + double_type, long_double_type, last_numeric_type = long_double_type, + cstring_type, string_type, pointer_type, custom_type +}; + +FMT_CONSTEXPR bool is_integral(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_integer_type; +} + +FMT_CONSTEXPR bool is_arithmetic(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_numeric_type; +} + +template +struct string_value { + const Char *value; + std::size_t size; +}; + +template +struct custom_value { + const void *value; + void (*format)(const void *arg, Context &ctx); +}; + +// A formatting argument value. +template +class value { + public: + typedef typename Context::char_type char_type; + + union { + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + string_value string; + string_value sstring; + string_value ustring; + custom_value custom; + }; + + FMT_CONSTEXPR value(int val = 0) : int_value(val) {} + value(unsigned val) { uint_value = val; } + value(long long val) { long_long_value = val; } + value(unsigned long long val) { ulong_long_value = val; } + value(double val) { double_value = val; } + value(long double val) { long_double_value = val; } + value(const char_type *val) { string.value = val; } + value(const signed char *val) { + static_assert(std::is_same::value, + "incompatible string types"); + sstring.value = val; + } + value(const unsigned char *val) { + static_assert(std::is_same::value, + "incompatible string types"); + ustring.value = val; + } + value(basic_string_view val) { + string.value = val.data(); + string.size = val.size(); + } + value(const void *val) { pointer = val; } + + template + explicit value(const T &val) { + custom.value = &val; + custom.format = &format_custom_arg; + } + + const named_arg_base &as_named_arg() { + return *static_cast*>(pointer); + } + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(const void *arg, Context &ctx) { + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + typename Context::template formatter_type::type f; + auto &&parse_ctx = ctx.parse_context(); + parse_ctx.advance_to(f.parse(parse_ctx)); + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } +}; + +// Value initializer used to delay conversion to value and reduce memory churn. +template +struct init { + T val; + static const type type_tag = TYPE; + + FMT_CONSTEXPR init(const T &v) : val(v) {} + FMT_CONSTEXPR operator value() const { return value(val); } +}; + +template +FMT_CONSTEXPR basic_format_arg make_arg(const T &value); + +#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ + template \ + FMT_CONSTEXPR init make_value(ArgType val) { \ + return static_cast(val); \ + } + +#define FMT_MAKE_VALUE_SAME(TAG, Type) \ + template \ + FMT_CONSTEXPR init make_value(Type val) { return val; } + +FMT_MAKE_VALUE(bool_type, bool, int) +FMT_MAKE_VALUE(int_type, short, int) +FMT_MAKE_VALUE(uint_type, unsigned short, unsigned) +FMT_MAKE_VALUE_SAME(int_type, int) +FMT_MAKE_VALUE_SAME(uint_type, unsigned) + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +typedef std::conditional::type + long_type; +FMT_MAKE_VALUE( + (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) +typedef std::conditional::type ulong_type; +FMT_MAKE_VALUE( + (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), + unsigned long, ulong_type) + +FMT_MAKE_VALUE_SAME(long_long_type, long long) +FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) +FMT_MAKE_VALUE(int_type, signed char, int) +FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) +FMT_MAKE_VALUE(char_type, char, int) + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +template +inline init make_value(wchar_t val) { + require_wchar(); + return static_cast(val); +} +#endif + +FMT_MAKE_VALUE(double_type, float, double) +FMT_MAKE_VALUE_SAME(double_type, double) +FMT_MAKE_VALUE_SAME(long_double_type, long double) + +// Formatting of wide strings into a narrow buffer and multibyte strings +// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). +FMT_MAKE_VALUE(cstring_type, typename C::char_type*, + const typename C::char_type*) +FMT_MAKE_VALUE(cstring_type, const typename C::char_type*, + const typename C::char_type*) + +FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) +FMT_MAKE_VALUE_SAME(cstring_type, const signed char*) +FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) +FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*) +FMT_MAKE_VALUE_SAME(string_type, basic_string_view) +FMT_MAKE_VALUE(string_type, + typename basic_string_view::type, + basic_string_view) +FMT_MAKE_VALUE(string_type, const std::basic_string&, + basic_string_view) +FMT_MAKE_VALUE(pointer_type, void*, const void*) +FMT_MAKE_VALUE_SAME(pointer_type, const void*) + +#if FMT_USE_NULLPTR +FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) +#endif + +// Formatting of arbitrary pointers is disallowed. If you want to output a +// pointer cast it to "void *" or "const void *". In particular, this forbids +// formatting of "[const] volatile char *" which is printed as bool by +// iostreams. +template +typename std::enable_if::value>::type + make_value(const T *) { + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); +} + +template +inline typename std::enable_if< + std::is_enum::value && convert_to_int::value, + init>::type + make_value(const T &val) { return static_cast(val); } + +template +inline typename std::enable_if< + std::is_constructible, T>::value, + init, string_type>>::type + make_value(const T &val) { return basic_string_view(val); } + +template +inline typename std::enable_if< + !convert_to_int::value && + !std::is_convertible>::value && + !std::is_constructible, T>::value, + // Implicit conversion to std::string is not handled here because it's + // unsafe: https://github.com/fmtlib/fmt/issues/729 + init>::type + make_value(const T &val) { return val; } + +template +init + make_value(const named_arg &val) { + basic_format_arg arg = make_arg(val.value); + std::memcpy(val.data, &arg, sizeof(arg)); + return static_cast(&val); +} + +// Maximum number of arguments with packed types. +enum { max_packed_args = 15 }; + +template +class arg_map; +} // namespace internal + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. +template +class basic_format_arg { + private: + internal::value value_; + internal::type type_; + + template + friend FMT_CONSTEXPR basic_format_arg + internal::make_arg(const T &value); + + template + friend FMT_CONSTEXPR typename internal::result_of::type + visit(Visitor &&vis, const basic_format_arg &arg); + + friend class basic_format_args; + friend class internal::arg_map; + + typedef typename Context::char_type char_type; + + public: + class handle { + public: + explicit handle(internal::custom_value custom): custom_(custom) {} + + void format(Context &ctx) const { custom_.format(custom_.value, ctx); } + + private: + internal::custom_value custom_; + }; + + FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {} + + FMT_EXPLICIT operator bool() const FMT_NOEXCEPT { + return type_ != internal::none_type; + } + + internal::type type() const { return type_; } + + bool is_integral() const { return internal::is_integral(type_); } + bool is_arithmetic() const { return internal::is_arithmetic(type_); } +}; + +struct monostate {}; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template +FMT_CONSTEXPR typename internal::result_of::type + visit(Visitor &&vis, const basic_format_arg &arg) { + typedef typename Context::char_type char_type; + switch (arg.type_) { + case internal::none_type: + break; + case internal::named_arg_type: + FMT_ASSERT(false, "invalid argument type"); + break; + case internal::int_type: + return vis(arg.value_.int_value); + case internal::uint_type: + return vis(arg.value_.uint_value); + case internal::long_long_type: + return vis(arg.value_.long_long_value); + case internal::ulong_long_type: + return vis(arg.value_.ulong_long_value); + case internal::bool_type: + return vis(arg.value_.int_value != 0); + case internal::char_type: + return vis(static_cast(arg.value_.int_value)); + case internal::double_type: + return vis(arg.value_.double_value); + case internal::long_double_type: + return vis(arg.value_.long_double_value); + case internal::cstring_type: + return vis(arg.value_.string.value); + case internal::string_type: + return vis(basic_string_view( + arg.value_.string.value, arg.value_.string.size)); + case internal::pointer_type: + return vis(arg.value_.pointer); + case internal::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); +} + +// Parsing context consisting of a format string range being parsed and an +// argument counter for automatic indexing. +template +class basic_parse_context : private ErrorHandler { + private: + basic_string_view format_str_; + int next_arg_id_; + + public: + typedef Char char_type; + typedef typename basic_string_view::iterator iterator; + + explicit FMT_CONSTEXPR basic_parse_context( + basic_string_view format_str, ErrorHandler eh = ErrorHandler()) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} + + // Returns an iterator to the beginning of the format string range being + // parsed. + FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT { + return format_str_.begin(); + } + + // Returns an iterator past the end of the format string range being parsed. + FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); } + + // Advances the begin iterator to ``it``. + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(internal::to_unsigned(it - begin())); + } + + // Returns the next argument index. + FMT_CONSTEXPR unsigned next_arg_id(); + + FMT_CONSTEXPR bool check_arg_id(unsigned) { + if (next_arg_id_ > 0) { + on_error("cannot switch from automatic to manual argument indexing"); + return false; + } + next_arg_id_ = -1; + return true; + } + void check_arg_id(basic_string_view) {} + + FMT_CONSTEXPR void on_error(const char *message) { + ErrorHandler::on_error(message); + } + + FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; } +}; + +typedef basic_parse_context parse_context; +typedef basic_parse_context wparse_context; + +namespace internal { +// A map from argument names to their values for named arguments. +template +class arg_map { + private: + arg_map(const arg_map &) = delete; + void operator=(const arg_map &) = delete; + + typedef typename Context::char_type char_type; + + struct entry { + basic_string_view name; + basic_format_arg arg; + }; + + entry *map_; + unsigned size_; + + void push_back(value val) { + const internal::named_arg_base &named = val.as_named_arg(); + map_[size_] = entry{named.name, named.template deserialize()}; + ++size_; + } + + public: + arg_map() : map_(FMT_NULL), size_(0) {} + void init(const basic_format_args &args); + ~arg_map() { delete [] map_; } + + basic_format_arg find(basic_string_view name) const { + // The list is unsorted, so just return the first matching name. + for (entry *it = map_, *end = map_ + size_; it != end; ++it) { + if (it->name == name) + return it->arg; + } + return basic_format_arg(); + } +}; + +template +class context_base { + public: + typedef OutputIt iterator; + + private: + basic_parse_context parse_context_; + iterator out_; + basic_format_args args_; + + protected: + typedef Char char_type; + typedef basic_format_arg format_arg; + + context_base(OutputIt out, basic_string_view format_str, + basic_format_args ctx_args) + : parse_context_(format_str), out_(out), args_(ctx_args) {} + + // Returns the argument with specified index. + format_arg do_get_arg(unsigned arg_id) { + format_arg arg = args_.get(arg_id); + if (!arg) + parse_context_.on_error("argument index out of range"); + return arg; + } + + // Checks if manual indexing is used and returns the argument with + // specified index. + format_arg get_arg(unsigned arg_id) { + return this->parse_context().check_arg_id(arg_id) ? + this->do_get_arg(arg_id) : format_arg(); + } + + public: + basic_parse_context &parse_context() { + return parse_context_; + } + + internal::error_handler error_handler() { + return parse_context_.error_handler(); + } + + void on_error(const char *message) { parse_context_.on_error(message); } + + // Returns an iterator to the beginning of the output range. + iterator out() { return out_; } + iterator begin() { return out_; } // deprecated + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { out_ = it; } + + basic_format_args args() const { return args_; } +}; + +// Extracts a reference to the container from back_insert_iterator. +template +inline Container &get_container(std::back_insert_iterator it) { + typedef std::back_insert_iterator bi_iterator; + struct accessor: bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; +} +} // namespace internal + +// Formatting context. +template +class basic_format_context : + public internal::context_base< + OutputIt, basic_format_context, Char> { + public: + /** The character type for the output. */ + typedef Char char_type; + + // using formatter_type = formatter; + template + struct formatter_type { typedef formatter type; }; + + private: + internal::arg_map map_; + + basic_format_context(const basic_format_context &) = delete; + void operator=(const basic_format_context &) = delete; + + typedef internal::context_base base; + typedef typename base::format_arg format_arg; + using base::get_arg; + + public: + using typename base::iterator; + + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + basic_format_context(OutputIt out, basic_string_view format_str, + basic_format_args ctx_args) + : base(out, format_str, ctx_args) {} + + format_arg next_arg() { + return this->do_get_arg(this->parse_context().next_arg_id()); + } + format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); } + + // Checks if manual indexing is used and returns the argument with the + // specified name. + format_arg get_arg(basic_string_view name); +}; + +template +struct buffer_context { + typedef basic_format_context< + std::back_insert_iterator>, Char> type; +}; +typedef buffer_context::type format_context; +typedef buffer_context::type wformat_context; + +namespace internal { +template +struct get_type { + typedef decltype(make_value( + declval::type&>())) value_type; + static const type value = value_type::type_tag; +}; + +template +FMT_CONSTEXPR11 unsigned long long get_types() { return 0; } + +template +FMT_CONSTEXPR11 unsigned long long get_types() { + return get_type::value | (get_types() << 4); +} + +template +FMT_CONSTEXPR basic_format_arg make_arg(const T &value) { + basic_format_arg arg; + arg.type_ = get_type::value; + arg.value_ = make_value(value); + return arg; +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_value(value); +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_arg(value); +} +} // namespace internal + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ +template +class format_arg_store { + private: + static const size_t NUM_ARGS = sizeof...(Args); + + // Packed is a macro on MinGW so use IS_PACKED instead. + static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; + + typedef typename std::conditional, basic_format_arg>::type value_type; + + // If the arguments are not packed, add one more element to mark the end. + static const size_t DATA_SIZE = + NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); + value_type data_[DATA_SIZE]; + + friend class basic_format_args; + + static FMT_CONSTEXPR11 long long get_types() { + return IS_PACKED ? + static_cast(internal::get_types()) : + -static_cast(NUM_ARGS); + } + + public: +#if FMT_USE_CONSTEXPR11 + static FMT_CONSTEXPR11 long long TYPES = get_types(); +#else + static const long long TYPES; +#endif + +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) + // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. + format_arg_store(const Args &... args) { + value_type init[DATA_SIZE] = + {internal::make_arg(args)...}; + std::memcpy(data_, init, sizeof(init)); + } +#else + format_arg_store(const Args &... args) + : data_{internal::make_arg(args)...} {} +#endif +}; + +#if !FMT_USE_CONSTEXPR11 +template +const long long format_arg_store::TYPES = get_types(); +#endif + +/** + \rst + Constructs an `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::context`. + \endrst + */ +template +inline format_arg_store + make_format_args(const Args & ... args) { + return format_arg_store(args...); +} + +template +inline format_arg_store + make_format_args(const Args & ... args) { + return format_arg_store(args...); +} + +/** Formatting arguments. */ +template +class basic_format_args { + public: + typedef unsigned size_type; + typedef basic_format_arg format_arg; + + private: + // To reduce compiled code size per formatting function call, types of first + // max_packed_args arguments are passed in the types_ field. + unsigned long long types_; + union { + // If the number of arguments is less than max_packed_args, the argument + // values are stored in values_, otherwise they are stored in args_. + // This is done to reduce compiled code size as storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const internal::value *values_; + const format_arg *args_; + }; + + typename internal::type type(unsigned index) const { + unsigned shift = index * 4; + unsigned long long mask = 0xf; + return static_cast( + (types_ & (mask << shift)) >> shift); + } + + friend class internal::arg_map; + + void set_data(const internal::value *values) { values_ = values; } + void set_data(const format_arg *args) { args_ = args; } + + format_arg do_get(size_type index) const { + format_arg arg; + long long signed_types = static_cast(types_); + if (signed_types < 0) { + unsigned long long num_args = + static_cast(-signed_types); + if (index < num_args) + arg = args_[index]; + return arg; + } + if (index > internal::max_packed_args) + return arg; + arg.type_ = type(index); + if (arg.type_ == internal::none_type) + return arg; + internal::value &val = arg.value_; + val = values_[index]; + return arg; + } + + public: + basic_format_args() : types_(0) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + basic_format_args(const format_arg_store &store) + : types_(static_cast(store.TYPES)) { + set_data(store.data_); + } + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + basic_format_args(const format_arg *args, size_type count) + : types_(-static_cast(count)) { + set_data(args); + } + + /** Returns the argument at specified index. */ + format_arg get(size_type index) const { + format_arg arg = do_get(index); + if (arg.type_ == internal::named_arg_type) + arg = arg.value_.as_named_arg().template deserialize(); + return arg; + } + + unsigned max_size() const { + long long signed_types = static_cast(types_); + return static_cast( + signed_types < 0 ? + -signed_types : static_cast(internal::max_packed_args)); + } +}; + +/** An alias to ``basic_format_args``. */ +// It is a separate type rather than a typedef to make symbols readable. +struct format_args: basic_format_args { + template + format_args(Args && ... arg) + : basic_format_args(std::forward(arg)...) {} +}; +struct wformat_args : basic_format_args { + template + wformat_args(Args && ... arg) + : basic_format_args(std::forward(arg)...) {} +}; + +namespace internal { +template +struct named_arg_base { + basic_string_view name; + + // Serialized value. + mutable char data[sizeof(basic_format_arg)]; + + named_arg_base(basic_string_view nm) : name(nm) {} + + template + basic_format_arg deserialize() const { + basic_format_arg arg; + std::memcpy(&arg, data, sizeof(basic_format_arg)); + return arg; + } +}; + +template +struct named_arg : named_arg_base { + const T &value; + + named_arg(basic_string_view name, const T &val) + : named_arg_base(name), value(val) {} +}; +} + +/** + \rst + Returns a named argument to be used in a formatting function. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ +template +inline internal::named_arg arg(string_view name, const T &arg) { + return internal::named_arg(name, arg); +} + +template +inline internal::named_arg arg(wstring_view name, const T &arg) { + return internal::named_arg(name, arg); +} + +// This function template is deleted intentionally to disable nested named +// arguments as in ``format("{}", arg("a", arg("b", 42)))``. +template +void arg(S, internal::named_arg) = delete; + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(fmt("{}"), 42). +struct compile_string {}; + +namespace internal { +// If S is a format string type, format_string_traints::char_type gives its +// character type. +template +struct format_string_traits { + private: + // Use constructability as a way to detect if format_string_traits is + // specialized because other methods are broken on MSVC2013. + format_string_traits(); +}; + +template +struct format_string_traits_base { typedef Char char_type; }; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits> : + format_string_traits_base {}; + +template +struct format_string_traits< + S, typename std::enable_if, S>::value>::type> : + format_string_traits_base {}; + +template +struct is_format_string : + std::integral_constant< + bool, std::is_constructible>::value> {}; + +template +struct is_compile_string : + std::integral_constant::value> {}; + +template +inline typename std::enable_if::value>::type + check_format_string(const S &) {} +template +typename std::enable_if::value>::type + check_format_string(S); + +template +std::basic_string vformat( + basic_string_view format_str, + basic_format_args::type> args); +} // namespace internal + +format_context::iterator vformat_to( + internal::buffer &buf, string_view format_str, format_args args); +wformat_context::iterator vformat_to( + internal::wbuffer &buf, wstring_view format_str, wformat_args args); + +template +struct is_contiguous : std::false_type {}; + +template +struct is_contiguous> : std::true_type {}; + +template +struct is_contiguous> : std::true_type {}; + +/** Formats a string and writes the output to ``out``. */ +template +typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + vformat_to(std::back_insert_iterator out, + string_view format_str, format_args args) { + internal::container_buffer buf(internal::get_container(out)); + vformat_to(buf, format_str, args); + return out; +} + +template +typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + vformat_to(std::back_insert_iterator out, + wstring_view format_str, wformat_args args) { + internal::container_buffer buf(internal::get_container(out)); + vformat_to(buf, format_str, args); + return out; +} + +template +inline typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + format_to(std::back_insert_iterator out, + string_view format_str, const Args & ... args) { + format_arg_store as{args...}; + return vformat_to(out, format_str, as); +} + +template +inline typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + format_to(std::back_insert_iterator out, + wstring_view format_str, const Args & ... args) { + return vformat_to(out, format_str, + make_format_args(args...)); +} + +template < + typename String, + typename Char = typename internal::format_string_traits::char_type> +inline std::basic_string vformat( + const String &format_str, + basic_format_args::type> args) { + // Convert format string to string_view to reduce the number of overloads. + return internal::vformat(basic_string_view(format_str), args); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}", 42); + \endrst +*/ +template +inline std::basic_string< + typename internal::format_string_traits::char_type> + format(const String &format_str, const Args & ... args) { + internal::check_format_string(format_str); + // This should be just + // return vformat(format_str, make_format_args(args...)); + // but gcc has trouble optimizing the latter, so break it down. + typedef typename internal::format_string_traits::char_type char_t; + typedef typename buffer_context::type context_t; + format_arg_store as{args...}; + return internal::vformat( + basic_string_view(format_str), basic_format_args(as)); +} + +FMT_API void vprint(std::FILE *f, string_view format_str, format_args args); +FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template +inline void print(std::FILE *f, string_view format_str, const Args & ... args) { + format_arg_store as(args...); + vprint(f, format_str, as); +} +/** + Prints formatted data to the file *f* which should be in wide-oriented mode + set via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. + */ +template +inline void print(std::FILE *f, wstring_view format_str, + const Args & ... args) { + format_arg_store as(args...); + vprint(f, format_str, as); +} + +FMT_API void vprint(string_view format_str, format_args args); +FMT_API void vprint(wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template +inline void print(string_view format_str, const Args & ... args) { + format_arg_store as{args...}; + vprint(format_str, as); +} + +template +inline void print(wstring_view format_str, const Args & ... args) { + format_arg_store as(args...); + vprint(format_str, as); +} +FMT_END_NAMESPACE + +#endif // FMT_CORE_H_ diff --git a/opt/fmt-5.2.1/include/fmt/format-inl.h b/opt/fmt-5.2.1/include/fmt/format-inl.h new file mode 100644 index 00000000..56c4d581 --- /dev/null +++ b/opt/fmt-5.2.1/include/fmt/format-inl.h @@ -0,0 +1,866 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#include "format.h" + +#include + +#include +#include +#include +#include +#include +#include // for std::ptrdiff_t +#include // for std::memmove +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include +#endif + +#if FMT_USE_WINDOWS_H +# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include +# else +# define NOMINMAX +# include +# undef NOMINMAX +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +inline fmt::internal::null<> strerror_r(int, char *, ...) { + return fmt::internal::null<>(); +} +inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::null<>(); +} + +FMT_BEGIN_NAMESPACE + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +typedef void (*FormatFunc)(internal::buffer &, int, string_view); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); + + class dispatcher { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const dispatcher &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } + + public: + dispatcher(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return dispatcher(error_code, buffer, buffer_size).run(); +} + +void format_error_code(internal::buffer &out, int error_code, + string_view message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::int_traits::main_type main_type; + main_type abs_value = static_cast(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::count_digits(abs_value); + writer w(out); + if (message.size() <= inline_buffer_size - error_code_size) { + w.write(message); + w.write(SEP); + } + w.write(ERROR_STR); + w.write(error_code); + assert(out.size() <= inline_buffer_size); +} + +void report_error(FormatFunc func, int error_code, + string_view message) FMT_NOEXCEPT { + memory_buffer full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} +} // namespace + +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +class locale { + private: + std::locale locale_; + + public: + explicit locale(std::locale loc = std::locale()) : locale_(loc) {} + std::locale get() { return locale_; } +}; + +FMT_FUNC size_t internal::count_code_points(u8string_view s) { + const char8_t *data = s.data(); + int num_code_points = 0; + for (size_t i = 0, size = s.size(); i != size; ++i) { + if ((data[i].value & 0xc0) != 0x80) + ++num_code_points; + } + return num_code_points; +} + +template +FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { + std::locale loc = lp ? lp->locale().get() : std::locale(); + return std::use_facet>(loc).thousands_sep(); +} +#else +template +FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { + return FMT_STATIC_THOUSANDS_SEPARATOR; +} +#endif + +FMT_FUNC void system_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + format_system_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +namespace internal { +template +int char_traits::format_float( + char *buffer, std::size_t size, const char *format, int precision, T value) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); +} + +template +int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, int precision, + T value) { + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, value) : + FMT_SWPRINTF(buffer, size, format, precision, value); +} + +template +const char basic_data::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template +const uint32_t basic_data::POWERS_OF_10_32[] = { + 1, FMT_POWERS_OF_10(1) +}; + +template +const uint32_t basic_data::ZERO_OR_POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template +const uint64_t basic_data::ZERO_OR_POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(1000000000ull), + 10000000000000000000ull +}; + +// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. +// These are generated by support/compute-powers.py. +template +const uint64_t basic_data::POW10_SIGNIFICANDS[] = { + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, + 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, + 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, + 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, + 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, + 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, +}; + +// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding +// to significands above. +template +const int16_t basic_data::POW10_EXPONENTS[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, + -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, + -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, + -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, + -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, + 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, + 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, + 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 +}; + +template const char basic_data::RESET_COLOR[] = "\x1b[0m"; +template const wchar_t basic_data::WRESET_COLOR[] = L"\x1b[0m"; + +// A handmade floating-point number f * pow(2, e). +class fp { + private: + typedef uint64_t significand_type; + + // All sizes are in bits. + static FMT_CONSTEXPR_DECL const int char_size = + std::numeric_limits::digits; + // Subtract 1 to account for an implicit most significant bit in the + // normalized form. + static FMT_CONSTEXPR_DECL const int double_significand_size = + std::numeric_limits::digits - 1; + static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = + 1ull << double_significand_size; + + public: + significand_type f; + int e; + + static FMT_CONSTEXPR_DECL const int significand_size = + sizeof(significand_type) * char_size; + + fp(): f(0), e(0) {} + fp(uint64_t f, int e): f(f), e(e) {} + + // Constructs fp from an IEEE754 double. It is a template to prevent compile + // errors on platforms where double is not IEEE754. + template + explicit fp(Double d) { + // Assume double is in the format [sign][exponent][significand]. + typedef std::numeric_limits limits; + const int double_size = static_cast(sizeof(Double) * char_size); + const int exponent_size = + double_size - double_significand_size - 1; // -1 for sign + const uint64_t significand_mask = implicit_bit - 1; + const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask; + const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; + auto u = bit_cast(d); + auto biased_e = (u & exponent_mask) >> double_significand_size; + f = u & significand_mask; + if (biased_e != 0) + f += implicit_bit; + else + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + e = static_cast(biased_e - exponent_bias - double_significand_size); + } + + // Normalizes the value converted from double and multiplied by (1 << SHIFT). + template + void normalize() { + // Handle subnormals. + auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((f & shifted_implicit_bit) == 0) { + f <<= 1; + --e; + } + // Subtract 1 to account for hidden bit. + auto offset = significand_size - double_significand_size - SHIFT - 1; + f <<= offset; + e -= offset; + } + + // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where + // a boundary is a value half way between the number and its predecessor + // (lower) or successor (upper). The upper boundary is normalized and lower + // has the same exponent but may be not normalized. + void compute_boundaries(fp &lower, fp &upper) const { + lower = f == implicit_bit ? + fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); + upper = fp((f << 1) + 1, e - 1); + upper.normalize<1>(); // 1 is to account for the exponent shift above. + lower.f <<= lower.e - upper.e; + lower.e = upper.e; + } +}; + +// Returns an fp number representing x - y. Result may not be normalized. +inline fp operator-(fp x, fp y) { + FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands"); + return fp(x.f - y.f, x.e); +} + +// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest +// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized. +FMT_API fp operator*(fp x, fp y); + +// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its +// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3. +FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent); + +FMT_FUNC fp operator*(fp x, fp y) { + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = x.f >> 32, b = x.f & mask; + uint64_t c = y.f >> 32, d = y.f & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); +} + +FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) { + const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) + int index = static_cast(std::ceil( + (min_exponent + fp::significand_size - 1) * one_over_log2_10)); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); +} + +// Generates output using Grisu2 digit-gen algorithm. +FMT_FUNC void grisu2_gen_digits( + const fp &scaled_value, const fp &scaled_upper, uint64_t delta, + char *buffer, size_t &size, int &dec_exp) { + internal::fp one(1ull << -scaled_upper.e, scaled_upper.e); + // hi (p1 in Grisu) contains the most significant digits of scaled_upper. + // hi = floor(scaled_upper / one). + uint32_t hi = static_cast(scaled_upper.f >> -one.e); + // lo (p2 in Grisu) contains the least significants digits of scaled_upper. + // lo = scaled_upper mod 1. + uint64_t lo = scaled_upper.f & (one.f - 1); + size = 0; + auto exp = count_digits(hi); // kappa in Grisu. + while (exp > 0) { + uint32_t digit = 0; + // This optimization by miloyip reduces the number of integer divisions by + // one per iteration. + switch (exp) { + case 10: digit = hi / 1000000000; hi %= 1000000000; break; + case 9: digit = hi / 100000000; hi %= 100000000; break; + case 8: digit = hi / 10000000; hi %= 10000000; break; + case 7: digit = hi / 1000000; hi %= 1000000; break; + case 6: digit = hi / 100000; hi %= 100000; break; + case 5: digit = hi / 10000; hi %= 10000; break; + case 4: digit = hi / 1000; hi %= 1000; break; + case 3: digit = hi / 100; hi %= 100; break; + case 2: digit = hi / 10; hi %= 10; break; + case 1: digit = hi; hi = 0; break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + if (digit != 0 || size != 0) + buffer[size++] = static_cast('0' + digit); + --exp; + uint64_t remainder = (static_cast(hi) << -one.e) + lo; + if (remainder <= delta) { + dec_exp += exp; + // TODO: use scaled_value + (void)scaled_value; + return; + } + } + for (;;) { + lo *= 10; + delta *= 10; + char digit = static_cast(lo >> -one.e); + if (digit != 0 || size != 0) + buffer[size++] = static_cast('0' + digit); + lo &= one.f - 1; + --exp; + if (lo < delta) { + dec_exp += exp; + return; + } + } +} + +FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size, + int &dec_exp) { + FMT_ASSERT(value > 0, "value is nonpositive"); + fp fp_value(value); + fp lower, upper; // w^- and w^+ in the Grisu paper. + fp_value.compute_boundaries(lower, upper); + // Find a cached power of 10 close to 1 / upper. + const int min_exp = -60; // alpha in Grisu. + auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. + min_exp - (upper.e + fp::significand_size), dec_exp); + dec_exp = -dec_exp; + fp_value.normalize(); + fp scaled_value = fp_value * dec_pow; + fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu. + fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu. + ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. + --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. + uint64_t delta = scaled_upper.f - scaled_lower.f; + grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp); +} + +FMT_FUNC void round(char *buffer, size_t &size, int &exp, + int digits_to_remove) { + size -= to_unsigned(digits_to_remove); + exp += digits_to_remove; + int digit = buffer[size] - '0'; + // TODO: proper rounding and carry + if (digit > 5 || (digit == 5 && (digits_to_remove > 1 || + (buffer[size - 1] - '0') % 2) != 0)) { + ++buffer[size - 1]; + } +} + +// Writes the exponent exp in the form "[+-]d{1,3}" to buffer. +FMT_FUNC char *write_exponent(char *buffer, int exp) { + FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); + if (exp < 0) { + *buffer++ = '-'; + exp = -exp; + } else { + *buffer++ = '+'; + } + if (exp >= 100) { + *buffer++ = static_cast('0' + exp / 100); + exp %= 100; + const char *d = data::DIGITS + exp * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } else { + const char *d = data::DIGITS + exp * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + return buffer; +} + +FMT_FUNC void format_exp_notation( + char *buffer, size_t &size, int exp, int precision, bool upper) { + // Insert a decimal point after the first digit and add an exponent. + std::memmove(buffer + 2, buffer + 1, size - 1); + buffer[1] = '.'; + exp += static_cast(size) - 1; + int num_digits = precision - static_cast(size) + 1; + if (num_digits > 0) { + std::uninitialized_fill_n(buffer + size + 1, num_digits, '0'); + size += to_unsigned(num_digits); + } else if (num_digits < 0) { + round(buffer, size, exp, -num_digits); + } + char *p = buffer + size + 1; + *p++ = upper ? 'E' : 'e'; + size = to_unsigned(write_exponent(p, exp) - buffer); +} + +// Prettifies the output of the Grisu2 algorithm. +// The number is given as v = buffer * 10^exp. +FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp, + int precision, bool upper) { + // pow(10, full_exp - 1) <= v <= pow(10, full_exp). + int int_size = static_cast(size); + int full_exp = int_size + exp; + const int exp_threshold = 21; + if (int_size <= full_exp && full_exp <= exp_threshold) { + // 1234e7 -> 12340000000[.0+] + std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0'); + char *p = buffer + full_exp; + if (precision > 0) { + *p++ = '.'; + std::uninitialized_fill_n(p, precision, '0'); + p += precision; + } + size = to_unsigned(p - buffer); + } else if (0 < full_exp && full_exp <= exp_threshold) { + // 1234e-2 -> 12.34[0+] + int fractional_size = -exp; + std::memmove(buffer + full_exp + 1, buffer + full_exp, + to_unsigned(fractional_size)); + buffer[full_exp] = '.'; + int num_zeros = precision - fractional_size; + if (num_zeros > 0) { + std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0'); + size += to_unsigned(num_zeros); + } + ++size; + } else if (-6 < full_exp && full_exp <= 0) { + // 1234e-6 -> 0.001234 + int offset = 2 - full_exp; + std::memmove(buffer + offset, buffer, size); + buffer[0] = '0'; + buffer[1] = '.'; + std::uninitialized_fill_n(buffer + 2, -full_exp, '0'); + size = to_unsigned(int_size + offset); + } else { + format_exp_notation(buffer, size, exp, precision, upper); + } +} + +#if FMT_CLANG_VERSION +# define FMT_FALLTHROUGH [[clang::fallthrough]]; +#elif FMT_GCC_VERSION >= 700 +# define FMT_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define FMT_FALLTHROUGH +#endif + +// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any +// guarantees on the shortness of the result. +FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type, + int precision, bool write_decimal_point) { + FMT_ASSERT(value >= 0, "value is negative"); + int dec_exp = 0; // K in Grisu. + if (value > 0) { + grisu2_format_positive(value, buffer, size, dec_exp); + } else { + *buffer = '0'; + size = 1; + } + const int default_precision = 6; + if (precision < 0) + precision = default_precision; + bool upper = false; + switch (type) { + case 'G': + upper = true; + FMT_FALLTHROUGH + case '\0': case 'g': { + int digits_to_remove = static_cast(size) - precision; + if (digits_to_remove > 0) { + round(buffer, size, dec_exp, digits_to_remove); + // Remove trailing zeros. + while (size > 0 && buffer[size - 1] == '0') { + --size; + ++dec_exp; + } + } + precision = 0; + break; + } + case 'F': + upper = true; + FMT_FALLTHROUGH + case 'f': { + int digits_to_remove = -dec_exp - precision; + if (digits_to_remove > 0) { + if (digits_to_remove >= static_cast(size)) + digits_to_remove = static_cast(size) - 1; + round(buffer, size, dec_exp, digits_to_remove); + } + break; + } + case 'e': case 'E': + format_exp_notation(buffer, size, dec_exp, precision, type == 'E'); + return; + } + if (write_decimal_point && precision < 1) + precision = 1; + grisu2_prettify(buffer, size, dec_exp, precision, upper); +} +} // namespace internal + +#if FMT_USE_WINDOWS_H + +FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (s.size() > INT_MAX) + FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); + int s_size = static_cast(s.size()); + if (s_size == 0) { + // MultiByteToWideChar does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return; + } + + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { + if (int error_code = convert(s)) { + FMT_THROW(windows_error(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { + if (s.size() > INT_MAX) + return ERROR_INVALID_PARAMETER; + int s_size = static_cast(s.size()); + if (s_size == 0) { + // WideCharToMultiByte does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return 0; + } + + int length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void windows_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + internal::format_windows_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +FMT_FUNC void internal::format_windows_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + wmemory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + wchar_t *system_message = &buf[0]; + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast(buf.size()), FMT_NULL); + if (result != 0) { + utf16_to_utf8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + writer w(out); + w.write(message); + w.write(": "); + w.write(utf8_message); + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void format_system_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + memory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + char *system_message = &buf[0]; + int result = safe_strerror(error_code, system_message, buf.size()); + if (result == 0) { + writer w(out); + w.write(message); + w.write(": "); + w.write(system_message); + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +template +void basic_fixed_buffer::grow(std::size_t) { + FMT_THROW(std::runtime_error("buffer overflow")); +} + +FMT_FUNC void internal::error_handler::on_error(const char *message) { + FMT_THROW(format_error(message)); +} + +FMT_FUNC void report_system_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void report_windows_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) { + memory_buffer buffer; + vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), 1, buffer.size(), f); +} + +FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) { + wmemory_buffer buffer; + vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f); +} + +FMT_FUNC void vprint(string_view format_str, format_args args) { + vprint(stdout, format_str, args); +} + +FMT_FUNC void vprint(wstring_view format_str, wformat_args args) { + vprint(stdout, format_str, args); +} + +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +FMT_FUNC locale locale_provider::locale() { return fmt::locale(); } +#endif + +FMT_END_NAMESPACE + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif // FMT_FORMAT_INL_H_ diff --git a/opt/fmt-5.2.1/include/fmt/format.h b/opt/fmt-5.2.1/include/fmt/format.h new file mode 100644 index 00000000..9f522f39 --- /dev/null +++ b/opt/fmt-5.2.1/include/fmt/format.h @@ -0,0 +1,3720 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __clang__ +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#ifdef __INTEL_COMPILER +# define FMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +# define FMT_ICC_VERSION __ICL +#else +# define FMT_ICC_VERSION 0 +#endif + +#ifdef __NVCC__ +# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +#else +# define FMT_CUDA_VERSION 0 +#endif + +#include "core.h" + +#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION +# pragma GCC diagnostic push + +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +# pragma GCC diagnostic ignored "-Wshadow" + +// Disable the warning about implicit conversions that may change the sign of +// an integer; silencing it otherwise would require many explicit casts. +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +# if FMT_CLANG_VERSION +# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" +# endif + +#ifdef _SECURE_SCL +# define FMT_SECURE_SCL _SECURE_SCL +#else +# define FMT_SECURE_SCL 0 +#endif + +#if FMT_SECURE_SCL +# include +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VER +FMT_BEGIN_NAMESPACE +namespace internal { +template +inline void do_throw(const Exception &x) { + // Silence unreachable code warnings in MSVC because these are nearly + // impossible to fix in a generic code. + volatile bool b = true; + if (b) + throw x; +} +} +FMT_END_NAMESPACE +# define FMT_THROW(x) fmt::internal::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) do { static_cast(sizeof(x)); assert(false); } while(false); +# endif +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc +// must support UDLs. +# if (FMT_HAS_FEATURE(cxx_user_literals) || \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ + (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || \ + FMT_ICC_VERSION >= 1500 || FMT_CUDA_VERSION >= 700) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// EDG C++ Front End based compilers (icc, nvcc) do not currently support UDL +// templates. +#if FMT_USE_USER_DEFINED_LITERALS && \ + FMT_ICC_VERSION == 0 && \ + FMT_CUDA_VERSION == 0 && \ + ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \ + (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304)) +# define FMT_UDL_TEMPLATE 1 +#else +# define FMT_UDL_TEMPLATE 0 +#endif + +#ifndef FMT_USE_EXTERN_TEMPLATES +# ifndef FMT_HEADER_ONLY +# define FMT_USE_EXTERN_TEMPLATES \ + ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \ + (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) +# else +# define FMT_USE_EXTERN_TEMPLATES 0 +# endif +#endif + +#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \ + FMT_MSC_VER >= 1600 +# define FMT_USE_TRAILING_RETURN 1 +#else +# define FMT_USE_TRAILING_RETURN 0 +#endif + +#ifndef FMT_USE_GRISU +# define FMT_USE_GRISU 0 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519 +#ifndef _MSC_VER +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif + +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// A workaround for gcc 4.4 that doesn't support union members with ctors. +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 404) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) +# define FMT_UNION struct +#else +# define FMT_UNION union +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) +# include // _BitScanReverse, _BitScanReverse64 + +FMT_BEGIN_NAMESPACE +namespace internal { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# ifndef __clang__ +# pragma intrinsic(_BitScanReverse) +# endif +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# if defined(_WIN64) && !defined(__clang__) +# pragma intrinsic(_BitScanReverse64) +# endif + +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An equivalent of `*reinterpret_cast(&source)` that doesn't produce +// undefined behavior (e.g. due to type aliasing). +// Example: uint64_t d = bit_cast(2.718); +template +inline Dest bit_cast(const Source& source) { + static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); + Dest dest; + std::memcpy(&dest, &source, sizeof(dest)); + return dest; +} + +// An implementation of begin and end for pre-C++11 compilers such as gcc 4. +template +FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin()) { + return c.begin(); +} +template +FMT_CONSTEXPR T *begin(T (&array)[N]) FMT_NOEXCEPT { return array; } +template +FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); } +template +FMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; } + +// For std::result_of in gcc 4.4. +template +struct function { + template + struct result { typedef Result type; }; +}; + +struct dummy_int { + int data[2]; + operator int() const { return 0; } +}; +typedef std::numeric_limits fputil; + +// Dummy implementations of system functions such as signbit and ecvt called +// if the latter are not available. +inline dummy_int signbit(...) { return dummy_int(); } +inline dummy_int _ecvt_s(...) { return dummy_int(); } +inline dummy_int isinf(...) { return dummy_int(); } +inline dummy_int _finite(...) { return dummy_int(); } +inline dummy_int isnan(...) { return dummy_int(); } +inline dummy_int _isnan(...) { return dummy_int(); } + +inline bool use_grisu() { + return FMT_USE_GRISU && std::numeric_limits::is_iec559; +} + +// Formats value using Grisu2 algorithm: +// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf +FMT_API void grisu2_format(double value, char *buffer, size_t &size, char type, + int precision, bool write_decimal_point); + +template +typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) { +#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 + return std::allocator_traits::allocate(alloc, n); +#else + return alloc.allocate(n); +#endif +} + +// A helper function to suppress bogus "conditional expression is constant" +// warnings. +template +inline T const_check(T value) { return value; } +} // namespace internal +FMT_END_NAMESPACE + +namespace std { +// Standard permits specialization of std::numeric_limits. This specialization +// is used to resolve ambiguity between isinf and std::isinf in glibc: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 +// and the same for isnan and signbit. +template <> +class numeric_limits : + public std::numeric_limits { + public: + // Portable version of isinf. + template + static bool isinfinity(T x) { + using namespace fmt::internal; + // The resolution "priority" is: + // isinf macro > std::isinf > ::isinf > fmt::internal::isinf + if (const_check(sizeof(isinf(x)) != sizeof(dummy_int))) + return isinf(x) != 0; + return !_finite(static_cast(x)); + } + + // Portable version of isnan. + template + static bool isnotanumber(T x) { + using namespace fmt::internal; + if (const_check(sizeof(isnan(x)) != sizeof(fmt::internal::dummy_int))) + return isnan(x) != 0; + return _isnan(static_cast(x)) != 0; + } + + // Portable version of signbit. + static bool isnegative(double x) { + using namespace fmt::internal; + if (const_check(sizeof(signbit(x)) != sizeof(fmt::internal::dummy_int))) + return signbit(x) != 0; + if (x < 0) return true; + if (!isnotanumber(x)) return false; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); + return sign != 0; + } +}; +} // namespace std + +FMT_BEGIN_NAMESPACE +template +class basic_writer; + +template +class output_range { + private: + OutputIt it_; + + // Unused yet. + typedef void sentinel; + sentinel end() const; + + public: + typedef OutputIt iterator; + typedef T value_type; + + explicit output_range(OutputIt it): it_(it) {} + OutputIt begin() const { return it_; } +}; + +// A range where begin() returns back_insert_iterator. +template +class back_insert_range: + public output_range> { + typedef output_range> base; + public: + typedef typename Container::value_type value_type; + + back_insert_range(Container &c): base(std::back_inserter(c)) {} + back_insert_range(typename base::iterator it): base(it) {} +}; + +typedef basic_writer> writer; +typedef basic_writer> wwriter; + +/** A formatting error such as invalid format string. */ +class format_error : public std::runtime_error { + public: + explicit format_error(const char *message) + : std::runtime_error(message) {} + + explicit format_error(const std::string &message) + : std::runtime_error(message) {} +}; + +namespace internal { + +#if FMT_SECURE_SCL +template +struct checked { typedef stdext::checked_array_iterator type; }; + +// Make a checked iterator to avoid warnings on MSVC. +template +inline stdext::checked_array_iterator make_checked(T *p, std::size_t size) { + return {p, size}; +} +#else +template +struct checked { typedef T *type; }; +template +inline T *make_checked(T *p, std::size_t) { return p; } +#endif + +template +template +void basic_buffer::append(const U *begin, const U *end) { + std::size_t new_size = size_ + internal::to_unsigned(end - begin); + reserve(new_size); + std::uninitialized_copy(begin, end, + internal::make_checked(ptr_, capacity_) + size_); + size_ = new_size; +} +} // namespace internal + +// A UTF-8 code unit type. +struct char8_t { + char value; + FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT { + return value != 0; + } +}; + +// A UTF-8 string view. +class u8string_view : public basic_string_view { + private: + typedef basic_string_view base; + + public: + using basic_string_view::basic_string_view; + using basic_string_view::char_type; + + u8string_view(const char *s) + : base(reinterpret_cast(s)) {} + + u8string_view(const char *s, size_t count) FMT_NOEXCEPT + : base(reinterpret_cast(s), count) {} +}; + +#if FMT_USE_USER_DEFINED_LITERALS +inline namespace literals { +inline u8string_view operator"" _u(const char *s, std::size_t n) { + return u8string_view(s, n); +} +} +#endif + +// A wrapper around std::locale used to reduce compile times since +// is very heavy. +class locale; + +class locale_provider { + public: + virtual ~locale_provider() {} + virtual fmt::locale locale(); +}; + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first ``SIZE`` elements stored in the object itself. + + You can use one of the following typedefs for common character types: + + +----------------+------------------------------+ + | Type | Definition | + +================+==============================+ + | memory_buffer | basic_memory_buffer | + +----------------+------------------------------+ + | wmemory_buffer | basic_memory_buffer | + +----------------+------------------------------+ + + **Example**:: + + fmt::memory_buffer out; + format_to(out, "The answer is {}.", 42); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +template > +class basic_memory_buffer: private Allocator, public internal::basic_buffer { + private: + T store_[SIZE]; + + // Deallocate memory allocated by the buffer. + void deallocate() { + T* data = this->data(); + if (data != store_) Allocator::deallocate(data, this->capacity()); + } + + protected: + void grow(std::size_t size) FMT_OVERRIDE; + + public: + explicit basic_memory_buffer(const Allocator &alloc = Allocator()) + : Allocator(alloc) { + this->set(store_, SIZE); + } + ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + void move(basic_memory_buffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + T* data = other.data(); + std::size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + std::uninitialized_copy(other.store_, other.store_ + size, + internal::make_checked(store_, capacity)); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + } + this->resize(size); + } + + public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + basic_memory_buffer(basic_memory_buffer &&other) { + move(other); + } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + basic_memory_buffer &operator=(basic_memory_buffer &&other) { + assert(this != &other); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { return *this; } +}; + +template +void basic_memory_buffer::grow(std::size_t size) { + std::size_t old_capacity = this->capacity(); + std::size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + T *old_data = this->data(); + T *new_data = internal::allocate(*this, new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(old_data, old_data + this->size(), + internal::make_checked(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) + Allocator::deallocate(old_data, old_capacity); +} + +typedef basic_memory_buffer memory_buffer; +typedef basic_memory_buffer wmemory_buffer; + +/** + \rst + A fixed-size memory buffer. For a dynamically growing buffer use + :class:`fmt::basic_memory_buffer`. + + Trying to increase the buffer size past the initial capacity will throw + ``std::runtime_error``. + \endrst + */ +template +class basic_fixed_buffer : public internal::basic_buffer { + public: + /** + \rst + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the + given size. + \endrst + */ + basic_fixed_buffer(Char *array, std::size_t size) { + this->set(array, size); + } + + /** + \rst + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the + size known at compile time. + \endrst + */ + template + explicit basic_fixed_buffer(Char (&array)[SIZE]) { + this->set(array, SIZE); + } + + protected: + FMT_API void grow(std::size_t size) FMT_OVERRIDE; +}; + +namespace internal { + +template +struct char_traits; + +template <> +struct char_traits { + // Formats a floating-point number. + template + FMT_API static int format_float(char *buffer, std::size_t size, + const char *format, int precision, T value); +}; + +template <> +struct char_traits { + template + FMT_API static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, int precision, T value); +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template int char_traits::format_float( + char *buffer, std::size_t size, const char* format, int precision, + double value); +extern template int char_traits::format_float( + char *buffer, std::size_t size, const char* format, int precision, + long double value); + +extern template int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + double value); +extern template int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + long double value); +#endif + +template +inline typename std::enable_if< + is_contiguous::value, + typename checked::type>::type + reserve(std::back_insert_iterator &it, std::size_t n) { + Container &c = internal::get_container(it); + std::size_t size = c.size(); + c.resize(size + n); + return make_checked(&c[size], n); +} + +template +inline Iterator &reserve(Iterator &it, std::size_t) { return it; } + +template +class null_terminating_iterator; + +template +FMT_CONSTEXPR_DECL const Char *pointer_from(null_terminating_iterator it); + +// An iterator that produces a null terminator on *end. This simplifies parsing +// and allows comparing the performance of processing a null-terminated string +// vs string_view. +template +class null_terminating_iterator { + public: + typedef std::ptrdiff_t difference_type; + typedef Char value_type; + typedef const Char* pointer; + typedef const Char& reference; + typedef std::random_access_iterator_tag iterator_category; + + null_terminating_iterator() : ptr_(0), end_(0) {} + + FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end) + : ptr_(ptr), end_(end) {} + + template + FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r) + : ptr_(r.begin()), end_(r.end()) {} + + FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) { + assert(ptr <= end_); + ptr_ = ptr; + return *this; + } + + FMT_CONSTEXPR Char operator*() const { + return ptr_ != end_ ? *ptr_ : 0; + } + + FMT_CONSTEXPR null_terminating_iterator operator++() { + ++ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator++(int) { + null_terminating_iterator result(*this); + ++ptr_; + return result; + } + + FMT_CONSTEXPR null_terminating_iterator operator--() { + --ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) { + return null_terminating_iterator(ptr_ + n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) { + return null_terminating_iterator(ptr_ - n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) { + ptr_ += n; + return *this; + } + + FMT_CONSTEXPR difference_type operator-( + null_terminating_iterator other) const { + return ptr_ - other.ptr_; + } + + FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const { + return ptr_ != other.ptr_; + } + + bool operator>=(null_terminating_iterator other) const { + return ptr_ >= other.ptr_; + } + + // This should be a friend specialization pointer_from but the latter + // doesn't compile by gcc 5.1 due to a compiler bug. + template + friend FMT_CONSTEXPR_DECL const CharT *pointer_from( + null_terminating_iterator it); + + private: + const Char *ptr_; + const Char *end_; +}; + +template +FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; } + +template +FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator it) { + return it.ptr_; +} + +// An output iterator that counts the number of objects written to it and +// discards them. +template +class counting_iterator { + private: + std::size_t count_; + mutable T blackhole_; + + public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + typedef counting_iterator _Unchecked_type; // Mark iterator as checked. + + counting_iterator(): count_(0) {} + + std::size_t count() const { return count_; } + + counting_iterator& operator++() { + ++count_; + return *this; + } + + counting_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + T &operator*() const { return blackhole_; } +}; + +// An output iterator that truncates the output and counts the number of objects +// written to it. +template +class truncating_iterator { + private: + typedef std::iterator_traits traits; + + OutputIt out_; + std::size_t limit_; + std::size_t count_; + mutable typename traits::value_type blackhole_; + + public: + typedef std::output_iterator_tag iterator_category; + typedef typename traits::value_type value_type; + typedef typename traits::difference_type difference_type; + typedef typename traits::pointer pointer; + typedef typename traits::reference reference; + typedef truncating_iterator _Unchecked_type; // Mark iterator as checked. + + truncating_iterator(OutputIt out, std::size_t limit) + : out_(out), limit_(limit), count_(0) {} + + OutputIt base() const { return out_; } + std::size_t count() const { return count_; } + + truncating_iterator& operator++() { + if (count_++ < limit_) + ++out_; + return *this; + } + + truncating_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + reference operator*() const { return count_ < limit_ ? *out_ : blackhole_; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template +FMT_CONSTEXPR typename std::enable_if< + std::numeric_limits::is_signed, bool>::type is_negative(T value) { + return value < 0; +} +template +FMT_CONSTEXPR typename std::enable_if< + !std::numeric_limits::is_signed, bool>::type is_negative(T) { + return false; +} + +template +struct int_traits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename std::conditional< + std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; +}; + +// Static data is placed in this class template to allow header-only +// configuration. +template +struct FMT_API basic_data { + static const uint32_t POWERS_OF_10_32[]; + static const uint32_t ZERO_OR_POWERS_OF_10_32[]; + static const uint64_t ZERO_OR_POWERS_OF_10_64[]; + static const uint64_t POW10_SIGNIFICANDS[]; + static const int16_t POW10_EXPONENTS[]; + static const char DIGITS[]; + static const char RESET_COLOR[]; + static const wchar_t WRESET_COLOR[]; +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template struct basic_data; +#endif + +typedef basic_data<> data; + +#ifdef FMT_BUILTIN_CLZLL +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline unsigned count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < data::ZERO_OR_POWERS_OF_10_64[t]) + 1; +} +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline unsigned count_digits(uint64_t n) { + unsigned count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +// Counts the number of code points in a UTF-8 string. +FMT_API size_t count_code_points(u8string_view s); + +#if FMT_HAS_CPP_ATTRIBUTE(always_inline) +# define FMT_ALWAYS_INLINE __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE +#endif + +template +inline char *lg(uint32_t n, Handler h) FMT_ALWAYS_INLINE; + +// Computes g = floor(log10(n)) and calls h.on(n); +template +inline char *lg(uint32_t n, Handler h) { + return n < 100 ? n < 10 ? h.template on<0>(n) : h.template on<1>(n) + : n < 1000000 + ? n < 10000 ? n < 1000 ? h.template on<2>(n) + : h.template on<3>(n) + : n < 100000 ? h.template on<4>(n) + : h.template on<5>(n) + : n < 100000000 ? n < 10000000 ? h.template on<6>(n) + : h.template on<7>(n) + : n < 1000000000 ? h.template on<8>(n) + : h.template on<9>(n); +} + +// An lg handler that formats a decimal number. +// Usage: lg(n, decimal_formatter(buffer)); +class decimal_formatter { + private: + char *buffer_; + + void write_pair(unsigned N, uint32_t index) { + std::memcpy(buffer_ + N, data::DIGITS + index * 2, 2); + } + + public: + explicit decimal_formatter(char *buf) : buffer_(buf) {} + + template char *on(uint32_t u) { + if (N == 0) { + *buffer_ = static_cast(u) + '0'; + } else if (N == 1) { + write_pair(0, u); + } else { + // The idea of using 4.32 fixed-point numbers is based on + // https://github.com/jeaiii/itoa + unsigned n = N - 1; + unsigned a = n / 5 * n * 53 / 16; + uint64_t t = ((1ULL << (32 + a)) / + data::ZERO_OR_POWERS_OF_10_32[n] + 1 - n / 9); + t = ((t * u) >> a) + n / 5 * 4; + write_pair(0, t >> 32); + for (unsigned i = 2; i < N; i += 2) { + t = 100ULL * static_cast(t); + write_pair(i, t >> 32); + } + if (N % 2 == 0) { + buffer_[N] = static_cast( + (10ULL * static_cast(t)) >> 32) + '0'; + } + } + return buffer_ += N + 1; + } +}; + +// An lg handler that formats a decimal number with a terminating null. +class decimal_formatter_null : public decimal_formatter { + public: + explicit decimal_formatter_null(char *buf) : decimal_formatter(buf) {} + + template char *on(uint32_t u) { + char *buf = decimal_formatter::on(u); + *buf = '\0'; + return buf; + } +}; + +#ifdef FMT_BUILTIN_CLZ +// Optional version of count_digits for better performance on 32-bit platforms. +inline unsigned count_digits(uint32_t n) { + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < data::ZERO_OR_POWERS_OF_10_32[t]) + 1; +} +#endif + +// A functor that doesn't add a thousands separator. +struct no_thousands_sep { + typedef char char_type; + + template + void operator()(Char *) {} +}; + +// A functor that adds a thousands separator. +template +class add_thousands_sep { + private: + basic_string_view sep_; + + // Index of a decimal digit with the least significant digit having index 0. + unsigned digit_index_; + + public: + typedef Char char_type; + + explicit add_thousands_sep(basic_string_view sep) + : sep_(sep), digit_index_(0) {} + + void operator()(Char *&buffer) { + if (++digit_index_ % 3 != 0) + return; + buffer -= sep_.size(); + std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), + internal::make_checked(buffer, sep_.size())); + } +}; + +template +FMT_API Char thousands_sep(locale_provider *lp); + +// Formats a decimal unsigned integer value writing into buffer. +// thousands_sep is a functor that is called after writing each char to +// add a thousands separator if necessary. +template +inline Char *format_decimal(Char *buffer, UInt value, unsigned num_digits, + ThousandsSep thousands_sep) { + buffer += num_digits; + Char *end = buffer; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast((value % 100) * 2); + value /= 100; + *--buffer = data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = data::DIGITS[index]; + thousands_sep(buffer); + } + if (value < 10) { + *--buffer = static_cast('0' + value); + return end; + } + unsigned index = static_cast(value * 2); + *--buffer = data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = data::DIGITS[index]; + return end; +} + +template +inline Iterator format_decimal( + Iterator out, UInt value, unsigned num_digits, ThousandsSep sep) { + typedef typename ThousandsSep::char_type char_type; + // Buffer should be large enough to hold all digits (digits10 + 1) and null. + char_type buffer[std::numeric_limits::digits10 + 2]; + format_decimal(buffer, value, num_digits, sep); + return std::copy_n(buffer, num_digits, out); +} + +template +inline It format_decimal(It out, UInt value, unsigned num_digits) { + return format_decimal(out, value, num_digits, no_thousands_sep()); +} + +template +inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits, + bool upper = false) { + buffer += num_digits; + Char *end = buffer; + do { + const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = (value & ((1 << BASE_BITS) - 1)); + *--buffer = BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]; + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +inline It format_uint(It out, UInt value, unsigned num_digits, + bool upper = false) { + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1) + // and null. + char buffer[std::numeric_limits::digits / BASE_BITS + 2]; + format_uint(buffer, value, num_digits, upper); + return std::copy_n(buffer, num_digits, out); +} + +#ifndef _WIN32 +# define FMT_USE_WINDOWS_H 0 +#elif !defined(FMT_USE_WINDOWS_H) +# define FMT_USE_WINDOWS_H 1 +#endif + +// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. +// All the functionality that relies on it will be disabled too. +#if FMT_USE_WINDOWS_H +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf8_to_utf16 { + private: + wmemory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator wstring_view() const { return wstring_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf16_to_utf8 { + private: + memory_buffer buffer_; + + public: + utf16_to_utf8() {} + FMT_API explicit utf16_to_utf8(wstring_view s); + operator string_view() const { return string_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + FMT_API int convert(wstring_view s); +}; + +FMT_API void format_windows_error(fmt::internal::buffer &out, int error_code, + fmt::string_view message) FMT_NOEXCEPT; +#endif + +template +struct null {}; +} // namespace internal + +enum alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum {SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8}; + +enum format_spec_tag {fill_tag, align_tag, width_tag, type_tag}; + +// Format specifier. +template +class format_spec { + private: + T value_; + + public: + typedef T value_type; + + explicit format_spec(T value) : value_(value) {} + + T value() const { return value_; } +}; + +// template +// typedef format_spec fill_spec; +template +class fill_spec : public format_spec { + public: + explicit fill_spec(Char value) : format_spec(value) {} +}; + +typedef format_spec width_spec; +typedef format_spec type_spec; + +// An empty format specifier. +struct empty_spec {}; + +// An alignment specifier. +struct align_spec : empty_spec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of AlignSpec and its subclasses. + wchar_t fill_; + alignment align_; + + FMT_CONSTEXPR align_spec( + unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) + : width_(width), fill_(fill), align_(align) {} + + FMT_CONSTEXPR unsigned width() const { return width_; } + FMT_CONSTEXPR wchar_t fill() const { return fill_; } + FMT_CONSTEXPR alignment align() const { return align_; } + + int precision() const { return -1; } +}; + +// Format specifiers. +template +class basic_format_specs : public align_spec { + public: + unsigned flags_; + int precision_; + Char type_; + + FMT_CONSTEXPR basic_format_specs( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} + + FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; } + FMT_CONSTEXPR int precision() const { return precision_; } + FMT_CONSTEXPR Char type() const { return type_; } +}; + +typedef basic_format_specs format_specs; + +template +FMT_CONSTEXPR unsigned basic_parse_context::next_arg_id() { + if (next_arg_id_ >= 0) + return internal::to_unsigned(next_arg_id_++); + on_error("cannot switch from manual to automatic argument indexing"); + return 0; +} + +namespace internal { + +template +struct format_string_traits< + S, typename std::enable_if::value>::type>: + format_string_traits_base {}; + +template +FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) { + switch (spec) { + case 0: case 'd': + handler.on_dec(); + break; + case 'x': case 'X': + handler.on_hex(); + break; + case 'b': case 'B': + handler.on_bin(); + break; + case 'o': + handler.on_oct(); + break; + case 'n': + handler.on_num(); + break; + default: + handler.on_error(); + } +} + +template +FMT_CONSTEXPR void handle_float_type_spec(Char spec, Handler &&handler) { + switch (spec) { + case 0: case 'g': case 'G': + handler.on_general(); + break; + case 'e': case 'E': + handler.on_exp(); + break; + case 'f': case 'F': + handler.on_fixed(); + break; + case 'a': case 'A': + handler.on_hex(); + break; + default: + handler.on_error(); + break; + } +} + +template +FMT_CONSTEXPR void handle_char_specs( + const basic_format_specs *specs, Handler &&handler) { + if (!specs) return handler.on_char(); + if (specs->type() && specs->type() != 'c') return handler.on_int(); + if (specs->align() == ALIGN_NUMERIC || specs->flag(~0u) != 0) + handler.on_error("invalid format specifier for char"); + handler.on_char(); +} + +template +FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler &&handler) { + if (spec == 0 || spec == 's') + handler.on_string(); + else if (spec == 'p') + handler.on_pointer(); + else + handler.on_error("invalid type specifier"); +} + +template +FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 's') + eh.on_error("invalid type specifier"); +} + +template +FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 'p') + eh.on_error("invalid type specifier"); +} + +template +class int_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_dec() {} + FMT_CONSTEXPR void on_hex() {} + FMT_CONSTEXPR void on_bin() {} + FMT_CONSTEXPR void on_oct() {} + FMT_CONSTEXPR void on_num() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template +class float_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit float_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_general() {} + FMT_CONSTEXPR void on_exp() {} + FMT_CONSTEXPR void on_fixed() {} + FMT_CONSTEXPR void on_hex() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template +class char_specs_checker : public ErrorHandler { + private: + CharType type_; + + public: + FMT_CONSTEXPR char_specs_checker(CharType type, ErrorHandler eh) + : ErrorHandler(eh), type_(type) {} + + FMT_CONSTEXPR void on_int() { + handle_int_type_spec(type_, int_type_checker(*this)); + } + FMT_CONSTEXPR void on_char() {} +}; + +template +class cstring_type_checker : public ErrorHandler { + public: + FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_string() {} + FMT_CONSTEXPR void on_pointer() {} +}; + +template +void arg_map::init(const basic_format_args &args) { + if (map_) + return; + map_ = new entry[args.max_size()]; + bool use_values = args.type(max_packed_args - 1) == internal::none_type; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::type arg_type = args.type(i); + switch (arg_type) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.values_[i]); + break; + default: + break; // Do nothing. + } + } + } + for (unsigned i = 0; ; ++i) { + switch (args.args_[i].type_) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.args_[i].value_); + break; + default: + break; // Do nothing. + } + } +} + +template +class arg_formatter_base { + public: + typedef typename Range::value_type char_type; + typedef decltype(internal::declval().begin()) iterator; + typedef basic_format_specs format_specs; + + private: + typedef basic_writer writer_type; + writer_type writer_; + format_specs *specs_; + + struct char_writer { + char_type value; + template + void operator()(It &&it) const { *it++ = value; } + }; + + void write_char(char_type value) { + if (specs_) + writer_.write_padded(1, *specs_, char_writer{value}); + else + writer_.write(value); + } + + void write_pointer(const void *p) { + format_specs specs = specs_ ? *specs_ : format_specs(); + specs.flags_ = HASH_FLAG; + specs.type_ = 'x'; + writer_.write_int(reinterpret_cast(p), specs); + } + + protected: + writer_type &writer() { return writer_; } + format_specs *spec() { return specs_; } + iterator out() { return writer_.out(); } + + void write(bool value) { + string_view sv(value ? "true" : "false"); + specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv); + } + + void write(const char_type *value) { + if (!value) + FMT_THROW(format_error("string pointer is null")); + auto length = std::char_traits::length(value); + basic_string_view sv(value, length); + specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv); + } + + public: + arg_formatter_base(Range r, format_specs *s): writer_(r), specs_(s) {} + + iterator operator()(monostate) { + FMT_ASSERT(false, "invalid argument type"); + return out(); + } + + template + typename std::enable_if::value, iterator>::type + operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same::value) { + if (specs_ && specs_->type_) + return (*this)(value ? 1 : 0); + write(value != 0); + } else if (std::is_same::value) { + internal::handle_char_specs( + specs_, char_spec_handler(*this, static_cast(value))); + } else { + specs_ ? writer_.write_int(value, *specs_) : writer_.write(value); + } + return out(); + } + + template + typename std::enable_if::value, iterator>::type + operator()(T value) { + writer_.write_double(value, specs_ ? *specs_ : format_specs()); + return out(); + } + + struct char_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + char_type value; + + char_spec_handler(arg_formatter_base& f, char_type val) + : formatter(f), value(val) {} + + void on_int() { + if (formatter.specs_) + formatter.writer_.write_int(value, *formatter.specs_); + else + formatter.writer_.write(value); + } + void on_char() { formatter.write_char(value); } + }; + + struct cstring_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + const char_type *value; + + cstring_spec_handler(arg_formatter_base &f, const char_type *val) + : formatter(f), value(val) {} + + void on_string() { formatter.write(value); } + void on_pointer() { formatter.write_pointer(value); } + }; + + iterator operator()(const char_type *value) { + if (!specs_) return write(value), out(); + internal::handle_cstring_type_spec( + specs_->type_, cstring_spec_handler(*this, value)); + return out(); + } + + iterator operator()(basic_string_view value) { + if (specs_) { + internal::check_string_type_spec( + specs_->type_, internal::error_handler()); + writer_.write_str(value, *specs_); + } else { + writer_.write(value); + } + return out(); + } + + iterator operator()(const void *value) { + if (specs_) + check_pointer_type_spec(specs_->type_, internal::error_handler()); + write_pointer(value); + return out(); + } +}; + +template +FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +} + +// DEPRECATED: Parses the input as an unsigned integer. This function assumes +// that the first character is a digit and presence of a non-digit character at +// the end. +// it: an iterator pointing to the beginning of the input range. +template +FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) { + assert('0' <= *it && *it <= '9'); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*it - '0'); + // Workaround for MSVC "setup_exception stack overflow" error: + auto next = it; + ++next; + it = next; + } while ('0' <= *it && *it <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR unsigned parse_nonnegative_int( + const Char *&begin, const Char *end, ErrorHandler &&eh) { + assert(begin != end && '0' <= *begin && *begin <= '9'); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*begin++ - '0'); + } while (begin != end && '0' <= *begin && *begin <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +template +class custom_formatter: public function { + private: + Context &ctx_; + + public: + explicit custom_formatter(Context &ctx): ctx_(ctx) {} + + bool operator()(typename basic_format_arg::handle h) const { + h.format(ctx_); + return true; + } + + template + bool operator()(T) const { return false; } +}; + +template +struct is_integer { + enum { + value = std::is_integral::value && !std::is_same::value && + !std::is_same::value && !std::is_same::value + }; +}; + +template +class width_checker: public function { + public: + explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {} + + template + FMT_CONSTEXPR + typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative width"); + return static_cast(value); + } + + template + FMT_CONSTEXPR typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { + handler_.on_error("width is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +template +class precision_checker: public function { + public: + explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {} + + template + FMT_CONSTEXPR typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative precision"); + return static_cast(value); + } + + template + FMT_CONSTEXPR typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { + handler_.on_error("precision is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +// A format specifier handler that sets fields in basic_format_specs. +template +class specs_setter { + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs &specs): + specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter &other) : specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; } + FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; } + FMT_CONSTEXPR void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } + FMT_CONSTEXPR void on_minus() { specs_.flags_ |= MINUS_FLAG; } + FMT_CONSTEXPR void on_space() { specs_.flags_ |= SIGN_FLAG; } + FMT_CONSTEXPR void on_hash() { specs_.flags_ |= HASH_FLAG; } + + FMT_CONSTEXPR void on_zero() { + specs_.align_ = ALIGN_NUMERIC; + specs_.fill_ = '0'; + } + + FMT_CONSTEXPR void on_width(unsigned width) { specs_.width_ = width; } + FMT_CONSTEXPR void on_precision(unsigned precision) { + specs_.precision_ = static_cast(precision); + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(Char type) { specs_.type_ = type; } + + protected: + basic_format_specs &specs_; +}; + +// A format specifier handler that checks if specifiers are consistent with the +// argument type. +template +class specs_checker : public Handler { + public: + FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type) + : Handler(handler), arg_type_(arg_type) {} + + FMT_CONSTEXPR specs_checker(const specs_checker &other) + : Handler(other), arg_type_(other.arg_type_) {} + + FMT_CONSTEXPR void on_align(alignment align) { + if (align == ALIGN_NUMERIC) + require_numeric_argument(); + Handler::on_align(align); + } + + FMT_CONSTEXPR void on_plus() { + check_sign(); + Handler::on_plus(); + } + + FMT_CONSTEXPR void on_minus() { + check_sign(); + Handler::on_minus(); + } + + FMT_CONSTEXPR void on_space() { + check_sign(); + Handler::on_space(); + } + + FMT_CONSTEXPR void on_hash() { + require_numeric_argument(); + Handler::on_hash(); + } + + FMT_CONSTEXPR void on_zero() { + require_numeric_argument(); + Handler::on_zero(); + } + + FMT_CONSTEXPR void end_precision() { + if (is_integral(arg_type_) || arg_type_ == pointer_type) + this->on_error("precision not allowed for this argument type"); + } + + private: + FMT_CONSTEXPR void require_numeric_argument() { + if (!is_arithmetic(arg_type_)) + this->on_error("format specifier requires numeric argument"); + } + + FMT_CONSTEXPR void check_sign() { + require_numeric_argument(); + if (is_integral(arg_type_) && arg_type_ != int_type && + arg_type_ != long_long_type && arg_type_ != internal::char_type) { + this->on_error("format specifier requires signed argument"); + } + } + + internal::type arg_type_; +}; + +template