diff --git a/.github/workflows/cpp-linter.yml b/.github/workflows/cpp-linter.yml index 1b851a2..11fe15d 100644 --- a/.github/workflows/cpp-linter.yml +++ b/.github/workflows/cpp-linter.yml @@ -24,7 +24,7 @@ jobs: style: file version: 15 files-changed-only: false - tidy-checks: "bugprone-a*,bugprone-b*,bugprone-c*,bugprone-d*,bugprone-em*,bugprone-ex*,bugprone-f*,bugprone-i*,bugprone-l*,bugprone-m*,bugprone-n*,bugprone-o*,bugprone-p*,bugprone-r*,bugprone-s*,bugprone-t*,bugprone-u*,bugprone-v*,performance-*,readability-a*,readability-b*,readability-c*,readability-d*,readability-e*,readability-f*,readability-i*,readability-m*,readability-n*,readability-o*,readability-q*,readability-r*,readability-si*,readability-st*,readability-u*,portability-*,clang-analyzer-*,cppcoreguidelines-avoid-ca*,cpp-coreguidelines-avoid-co*,cpp-coreguidelines-avoid-d*,cpp-coreguidelines-avoid-g*,cpp-coreguidelines-avoid-n*,cpp-coreguidelines-avoid-r*,cpp-coreguidelines-i*,cpp-coreguidelines-m*,cpp-coreguidelines-n*,cpp-coreguidelines-o*,cpp-coreguidelines-pr*,cpp-coreguidelines-pro-bounds-p*,cpp-coreguidelines-pro-t*,cpp-coreguidelines-r*,cpp-coreguidelines-s*,cpp-coreguidelines-v*" + tidy-checks: "bugprone-*,performance-*,readability-*,portability-*,clang-analyzer-*,cpp-coreguidelines-*,modernize-a*,modernize-c*,modernize-d*,modernize-l*,modernize-m*,modernize-p*,modernize-r*,modernize-s*,modernize-t*,modernize-un*,modernize-use-a*,modernize-use-b*,modernize-use-c*,modernize-use-d*,modernize-use-e*,modernize-use-n*,modernize-use-o*,modernize-use-s*,modernize-use-tran*,modernize-use-u*" database: "build/debug/gh-coverage/compile_commands.json" ignore: "build/debug/gh-coverage/_deps | build/debug/gh-coverage/CMakeFiles | src/utests.cpp | src/benchmark.cpp | src/util.hpp | .github" extra-args: "-O0 -Wall -Werror -Wshadow -Wextra -pedantic-errors -std=c++20" diff --git a/.gitignore b/.gitignore index d96f563..4a3d02b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ # Any compressed files *.tar.gz +*.tgz # Static analysis stuff .cache diff --git a/README.org b/README.org index 71e1f66..5ad43f0 100644 --- a/README.org +++ b/README.org @@ -20,6 +20,7 @@ @@html:GitHub code size in bytes@@ @@html:Codacy grade@@ @@html:@@ +@@html:@@ [[https://github.com/arbCoding/sac-format/actions/workflows/cpp-linter.yml][https://github.com/arbCoding/sac-format/actions/workflows/cpp-linter.yml/badge.svg]] sac-format is a single-header, statically linked library for reading binary diff --git a/coverity_build.sh b/coverity_build.sh new file mode 100755 index 0000000..4e926f3 --- /dev/null +++ b/coverity_build.sh @@ -0,0 +1,24 @@ +#!/bin/dash +base=$(pwd) +# Cleanup +if [ -e "$base/build/debug/gcc" ]; then + rm -rf "$base/build/debug/gcc" +fi +# Prepare to build +cmake --preset gcc-debug +# Prepare coverity scan +cd ./build/debug/gcc || exit +# Make sure it only captures the sac_format.hpp/.cpp pair for the library +cov-configure --config cov-conf/cov.xml --compiler g++ --comptype g++ \ + --template --xml-option=skip_file:".*/_deps/.*" \ + --xml-option=skip_file:".*/utests.cpp" \ + --xml-option=skip_file:".*/benchmark.cpp" \ + --xml-option=skip_file:".*/list_sac.cpp" +# Capture the ninja build +cov-build --config cov-conf/cov.xml --dir cov-int ninja +# Package for submission +tar czf sac-format.tgz cov-int +# Move to base dir +mv ./sac-format.tgz "$base/sac-format.tgz" +# Return home +cd "$base" || exit diff --git a/docs/index.html b/docs/index.html index 0a59631..7d4bd8b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,54 +1,55 @@ sac-format -

sac-format
C++20 SAC-file Library
V0.4.0
User Manual

Table of Contents

Windows 2022 Build Status +

sac-format
C++20 SAC-file Library
V0.4.0
User Manual

Windows 2022 Build Status Ubuntu 22.04 Build Status macOS 13 Build Status Code Coverage Codacy grade CodeFactor -CPP-Linter Results

1. Introduction

sac-format is a single-header statically linked library designed to make working +Coverity Scan Build Status +CPP-Linter Results

1. Introduction

sac-format is a single-header statically linked library designed to make working with binary SAC-files as easy as possible. Written in C++20, it follows a modern and easy to read programming-style while providing the high performance brought -by C++.

sac-format’s developed on GitHub!

Download an offline version of the documentation (PDF).

1.1. Why sac-format

sac-format is Free and Open Source Software (FOSS) released under the MIT +by C++.

sac-format’s developed on GitHub!

Download an offline version of the documentation (PDF).

1.1. Why sac-format

sac-format is Free and Open Source Software (FOSS) released under the MIT license. Anyone can use it, for any purpose (including proprietary software), anywhere in the world. sac-format is operating system agnostic and confirmed -working on Windows, macOS, and Linux systems.

1.1.1. Safe

sac-format is safe—it conforms to a strict set of C++ programming guidelines, +working on Windows, macOS, and Linux systems.

1.1.1. Safe

sac-format is safe—it conforms to a strict set of C++ programming guidelines, chosen to ensure safe code-execution. The guideline conformance list is in cpp-linter.yml and can be cross-referenced against this master list. Results of conformance checking are here.

Testing is an important part of software development; the sac-format library is extensively tested using the Catch2 testing framework. Everything from low-level binary conversions to high-level Trace reading/writing are tested and confirmed -working. Check and run the tests yourself. See the Testing section for more -information.

1.1.2. Fast

sac-format is fast—it’s written in C++, carefully optimized, and extensively +working. Check and run the tests yourself. See the Testing section for more +information.

1.1.2. Fast

sac-format is fast—it’s written in C++, carefully optimized, and extensively benchmarked. You can run the benchmarks yourself to find out how sac-format -performs on your system. See the Benchmarking section for more information.

1.1.3. Easy

sac-format is easy—single-header makes integration in any project simple. +performs on your system. See the Benchmarking section for more information.

1.1.3. Easy

sac-format is easy—single-header makes integration in any project simple. Building is a breeze with CMake, even on different platforms. Object-oriented -design makes use easy and intuitive. See the Quickstart section to get up and -running.

1.1.4. Small

sac-format is small—in total (header + implementation–excluding comments) the +design makes use easy and intuitive. See the Quickstart section to get up and +running.

1.1.4. Small

sac-format is small—in total (header + implementation–excluding comments) the library is under 2100∗ lines of code. Small size opens the door to using on any sort of hardware (old or new) and makes it easy to expand upon.

∗ This value includes only the library, excluding all testing/benchmarking and example codes. Including utests.cpp, benchmark.cpp, util.hpp, the example -program (list_sac), and sac-format totals just over 5100 lines of code.

1.1.5. Documented

sac-format is extensively documented—both online and in the code. Nothing’s +program (list_sac), and sac-format totals just over 5100 lines of code.

1.1.5. Documented

sac-format is extensively documented—both online and in the code. Nothing’s hidden—nothing’s obscured. Curious how something works? Check the -documentation and in-code comments.

1.1.6. Transparent

sac-format is transparent—all analysis and coverage information is publicly -available online.

1.1.7. Trace Class

sac-format includes the Trace class for seismic traces, providing high-level +documentation and in-code comments.

1.1.6. Transparent

sac-format is transparent—all analysis and coverage information is publicly +available online.

1.1.7. Trace Class

sac-format includes the Trace class for seismic traces, providing high-level object-oriented abstraction to seismic data. With the Trace class, you don’t need to worry about manually reading SAC-files word-by-word. It’s compatible with v6 and v7 SAC-files and can automatically detect the version upon reading. File output defaults to v7 SAC-files and there is a legacy_write function for v6 -output.

1.1.8. Low-Level I/O

If you want to roll your own SAC-file processing workflow you can use the +output.

1.1.8. Low-Level I/O

If you want to roll your own SAC-file processing workflow you can use the low-level I/O functionality built into sac-format. All functions tested and -confirmed working—they’re used to build the Trace class!

2. Quickstart

2.1. Manual Instructions

2.1.1. Build Instructions

Building is as easy as cloning the repository, running CMake for your preferred -build tool, and then building.

  1. GCC
    git clone https://github.com/arbCoding/sac-format.git
    +confirmed working—they’re used to build the Trace class!

2. Quickstart

2.1. Manual Instructions

2.1.1. Build Instructions

Building is as easy as cloning the repository, running CMake for your preferred +build tool, and then building.

  1. GCC
    git clone https://github.com/arbCoding/sac-format.git
     cmake --preset gcc-release
     cmake --build ./build/release/gcc
    -
  2. Clang
    git clone https://github.com/arbCoding/sac-format.git
    +
  3. Clang
    git clone https://github.com/arbCoding/sac-format.git
     cmake --preset clang-release
     cmake --build ./build/release/clang
    -

2.1.2. Use

To use link to the compiled library (libsac-format.a on Linux/macOS, -libsac-format.lib on Windows) and include src/sac_format.hpp.

2.2. Example Programs

2.2.1. list_sac

list_sac is a command line program that takes a single SAC-file as its input +

2.1.2. Use

To use link to the compiled library (libsac-format.a on Linux/macOS, +libsac-format.lib on Windows) and include src/sac_format.hpp.

2.2. Example Programs

2.2.1. list_sac

list_sac is a command line program that takes a single SAC-file as its input argument. It reads the SAC-file and outputs the header/footer information, as -well as the true size of the data1 and data2 vectors.

2.3. CMake Integration

To integrate sac-format into your CMake project, add it to your CMakeLists.txt.

include(FetchContent)
+well as the true size of the data1 and data2 vectors.

2.3. CMake Integration

To integrate sac-format into your CMake project, add it to your CMakeLists.txt.

include(FetchContent)
 set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
 FetchContent_Declare(sac-format
     GIT_REPOSITORY https://github.com/arbCoding/sac-format
@@ -65,7 +66,7 @@
 
 target_link_libraries_library(your_executable
     PRIVATE sac-format)
-

2.4. Example

2.4.1. Reading and Writing

#include <filesystem>
+

2.4. Example

2.4.1. Reading and Writing

#include <filesystem>
 #include <iostream>
 #include <sac_format.hpp>
 
@@ -86,8 +87,8 @@
     fs::remove(file);
     return EXIT_SUCCESS;
 }
-

3. Documentation

3.1. Trace class

The Trace class provides easy access to SAC-files in C++. Each SAC-file is a -Trace; therefore, each Trace object is a seismic trace (seismogram).

3.1.1. Reading SAC

SAC-files can be read in by using the parameterized constructor with a +

3. Documentation

3.1. Trace class

The Trace class provides easy access to SAC-files in C++. Each SAC-file is a +Trace; therefore, each Trace object is a seismic trace (seismogram).

3.1.1. Reading SAC

SAC-files can be read in by using the parameterized constructor with a std::filesystem::path (<filesystem>) or a std::string (<string>) variable that corresponds to the location of the SAC-file.

For example:

#include <filesystem>
 #include <sac_foramt.hpp>
@@ -97,34 +98,34 @@
   sacfmt::Trace anmo = Trace(my_file);
   return EXIT_SUCCESS;
 }
-

3.1.2. Writing SAC

Writing SAC files can be done using one of two write functions.

  1. v7 files

    Use write (for example trace.write(filename)).

  2. v6 files

    Use legacy_write (for example trace.legacy_write(filename)).

3.1.3. Getters and Setters

Every SAC variable is accessed via getters and setters of the same name.

  1. Example Getters
    • trace.npts()
    • trace.data1()
    • trace.kstnm()
  2. Example Setters
    • trace.kevnm("Event 1")
    • trace.evla(32.89)
    • trace.mag(3.21)
  3. Setter rules

    Most of the setters are only constrained by the parameter type +

3.1.2. Writing SAC

Writing SAC files can be done using one of two write functions.

  1. v7 files

    Use write (for example trace.write(filename)).

  2. v6 files

    Use legacy_write (for example trace.legacy_write(filename)).

3.1.3. Getters and Setters

Every SAC variable is accessed via getters and setters of the same name.

  1. Example Getters
    • trace.npts()
    • trace.data1()
    • trace.kstnm()
  2. Example Setters
    • trace.kevnm("Event 1")
    • trace.evla(32.89)
    • trace.mag(3.21)
  3. Setter rules

    Most of the setters are only constrained by the parameter type (single-precision, double-precision, boolean, etc.). Some setters are -constrained by additional rules.

    1. Required for sanity

      Rules here are required because the sac-format library assumes them (not +constrained by additional rules.

      1. Required for sanity

        Rules here are required because the sac-format library assumes them (not strictly required by the SAC format standard). For instance, the geometric functions assume certain bounds on latitudes and longitudes. sac-format -automatically imposes these rules.

        1. stla(input)

          Limited to \([-90, 90]\) degrees, input that is outside that range is reduced -using circular symmetry.

        2. stlo(input)

          Limited to \([-180, 180]\) degrees, input that is outside that range is reduced -using circular symmetry.

        3. evla(input)

          Limited to \([-90, 90]\) degrees, input that is outside that range is reduced -using circular symmetry.

        4. evlo(input)

          Limited to \([-180, 180]\) degrees, input that is outside that range is reduced -using circular symmetry.

      2. Require for safety

        Rules here are required by the SAC format standard. sac-format automatically -imposes these rules to prevent the creation of corrupt sac-files.

        1. npts(input)

          Because npts defines the size of the data vectors, changing this value will +automatically imposes these rules.

          1. stla(input)

            Limited to \([-90, 90]\) degrees, input that is outside that range is reduced +using circular symmetry.

          2. stlo(input)

            Limited to \([-180, 180]\) degrees, input that is outside that range is reduced +using circular symmetry.

          3. evla(input)

            Limited to \([-90, 90]\) degrees, input that is outside that range is reduced +using circular symmetry.

          4. evlo(input)

            Limited to \([-180, 180]\) degrees, input that is outside that range is reduced +using circular symmetry.

        2. Required for safety

          Rules here are required by the SAC format standard. sac-format automatically +imposes these rules to prevent the creation of corrupt sac-files.

          1. npts(input)

            Because npts defines the size of the data vectors, changing this value will change the size of data1 and data2∗. Increasing npts resizes the vectors (std::vector::resize) by placing zeros at the end of the vectors. Reducing npts resizes the vectors down to the first npts values.

            Therefore, care must be taken to maintain separate copies of data1 and -data2∗ if you plan to manipulate the original data after resizing.

            ∗ data2 has npts only if it is legal, otherwise it is of size 0.

          2. leven(input)

            Changing the value of leven potentially changes the legality of data2, it also +data2∗ if you plan to manipulate the original data after resizing.

            ∗ data2 has npts only if it is legal, otherwise it is of size 0.

          3. leven(input)

            Changing the value of leven potentially changes the legality of data2, it also potentially affects the value of iftype.

            If iftype\(>1\), then leven must be true (evenly sampled data). Therefore, if leven is made false in this scenario (unevenly sampled data) then iftype becomes unset∗.

            If changing leven makes data2 legal∗∗, then data2 is resized to have npts zeros.

            ∗ The SAC format defines the unset values for all data-types. For integers -(like iftype) it is the integer value -12345.

            ∗∗ If data2 was already legal, then it is unaffected.

          4. iftype(input)

            Changing the value of iftype poentially changes the legality of data2, it also potentially affects the value of leven.

            If leven is false, then iftype must be either 1 or unset. Therefore, changing +(like iftype) it is the integer value -12345.

            ∗∗ If data2 was already legal, then it is unaffected.

          5. iftype(input)

            Changing the value of iftype poentially changes the legality of data2, it also potentially affects the value of leven.

            If leven is false, then iftype must be either 1 or unset. Therefore, changing iftype to have a value \(>1\) requires that leven becomes true (evenly sampled -data).

            If changing iftype makes data2 legal∗, then data2 is resized to have npts zeros.

            ∗ If data2 was already legal, then it is unaffected.

          6. data1(input)

            If the size of data1 is changed, then npts must change to reflect the new size. -If data2 is legal, this adjusts its size to match as well.

          7. data2(input)

            If the size of data2 is changed to be larger than 0 and it is illegal, it is +data).

            If changing iftype makes data2 legal∗, then data2 is resized to have npts zeros.

            ∗ If data2 was already legal, then it is unaffected.

          8. data1(input)

            If the size of data1 is changed, then npts must change to reflect the new size. +If data2 is legal, this adjusts its size to match as well.

          9. data2(input)

            If the size of data2 is changed to be larger than 0 and it is illegal, it is made legal by setting iftype(2) (spectral-data).

            When the size of data2 changes, npts is updated to the new size and data1 is resized to match.

            If data2 is made illegal, its size is reduced to 0 while npts and data1 are -unaffected.

3.1.4. Internal Structure

The SAC-trace stores the data internally in a series of pre-allocated -std::array (<array>) container objects. Getters and setters access these via -a lookup table. The internal components are below:

  1. Lookup Table

    sac_map

  2. floats array
  3. doubles array
  4. ints array
  5. bools array
  6. strings array
  7. data array

3.1.5. Convenience Methods

  • calc_geometry

Calculate gcarc, dist, az, and baz assuming spherical Earth.

trace.stla(45.3);
+unaffected.

3.1.4. Internal Structure

The SAC-trace stores the data internally in a series of pre-allocated +std::array (<array>) container objects. Getters and setters access these via +a lookup table. The internal components are below:

  1. Lookup Table

    sac_map

  2. floats array
  3. doubles array
  4. ints array
  5. bools array
  6. strings array
  7. data array

3.1.5. Convenience Methods

  • calc_geometry

Calculate gcarc, dist, az, and baz assuming spherical Earth.

trace.stla(45.3);
 trace.stlo(34.5);
 trace.evla(18.5);
 trace.evlo(-34);
@@ -137,8 +138,8 @@
 
  • date

Return std::string formatted as YYYY-JJJ from nzyear and nzjday.

std::string date{trace.date()};
 
  • time

Return std::string formatted as HH:MM:SS.xxx from nzhour, nzmin, nzsec, and nzmsec.

std::string time{trace.time()};
-

3.1.6. Exceptions

sac-format throws exceptions of type sacfmt::io_error (inherits -std::exception) in the event of a failure to read/write a SAC-file.

3.2. Convenience Functions

  • degrees_to_radians

Convert decimal degrees to radians.

double radians{sacfmt::degrees_to_radians(degrees)};
+

3.1.6. Exceptions

sac-format throws exceptions of type sacfmt::io_error (inherits +std::exception) in the event of a failure to read/write a SAC-file.

3.2. Convenience Functions

  • degrees_to_radians

Convert decimal degrees to radians.

double radians{sacfmt::degrees_to_radians(degrees)};
 
  • radians_to_degrees

Convert radians to decimal degrees.

double degrees{sacfmt::radians_to_degrees(radians)};
 
  • gcarc

Calculate great-circle arc distance (spherical planet).

double gcarc{sacfmt::gcarc(latitude1, longitude1, latitude2, longitude2)};
 
  • azimuth

Calculate azimuth between two points (spherical planet).

double azimuth{sacfmt::azimuth(latitude2, longitude2, latitude1, longitude1)};
@@ -147,64 +148,64 @@
 
  • limit_180

Take arbitrary value of degrees and unwrap to \([-180, 180]\). Useful for longitude.

double degrees_limited{sacfmt::limit_180(degrees)};
 
  • limit_90

Take arbitrary value of degrees and unwrap to \([-90, 90]\). Useful for latitude.

double degrees_limited{sacfmt::limit_90(degrees)};
-

3.3. Low-Level I/O

Low-level I/O functions are discussed below.

  1. Binary conversion
    1. int_to_binary and binary_to_int

      Conversion pair for binary representation of integer values.

      const int input{10};
      +

3.3. Low-Level I/O

Low-level I/O functions are discussed below.

  1. Binary conversion
    1. int_to_binary and binary_to_int

      Conversion pair for binary representation of integer values.

      const int input{10};
       // sacfmt::word_one is alias for std::bitset<32> (one word)
       sacfmt::word_one binary{sacfmt::int_to_binary(input)};
       const int output{sacfmt::binary_to_int(binary)};
       std::cout << (input == output) << '\n';
      -
    2. float_to_binary and binary_to_float

      Conversion pair for binary representation of floating-point values.

      const float input{5F};
      +
    3. float_to_binary and binary_to_float

      Conversion pair for binary representation of floating-point values.

      const float input{5F};
       sacfmt::word_one binary{sacfmt::float_to_binary(input)};
       const float output{sacfmt::binary_to_float(binary)};
       std::cout << (input == output) << '\n';
      -
    4. double_to_binary and binary_to_double

      Conversion pair for binary representation of double-precision values.

      const double input{1e5};
      +
    5. double_to_binary and binary_to_double

      Conversion pair for binary representation of double-precision values.

      const double input{1e5};
       // sacfmt::word_two is alias for std::bitset<64> (two words)
       sacfmt::word_two binary{sacfmt::double_to_binary(input)};
       const double output{sacfmt::binary_to_double(binary)};
       std::cout << (input == output) << '\n';
      -
    6. string_to_binary and binary_to_string

      Conversion pair for binary representation of two-word (regular) string values.

      const std::string input{"NmlStrng"};
      +
    7. string_to_binary and binary_to_string

      Conversion pair for binary representation of two-word (regular) string values.

      const std::string input{"NmlStrng"};
       sacfmt::word_two binary{sacfmt::string_to_binary(input)};
       const std::string output{sacfmt::binary_to_string(binary)};
       std::cout << (input == output) << '\n';
      -
    8. long_string_to_binary and binary_to_long_string

      Conversion pair for binary representation of four-word (only kstnm) string +

  • long_string_to_binary and binary_to_long_string

    Conversion pair for binary representation of four-word (only kstnm) string values.

    const std::string input{"The Long String"};
     // sacfmt::word_four is alias for std::bitset<128> (four words)
     sacfmt::word_four binary{sacfmt::long_string_to_binary(input)};
     const std::string output{sacfmt::binary_to_long_string(binary)};
     std::cout << (input == output) << '\n';
    -
  • Reading/Writing

    NOTE that care must be taken when using them to ensure that safe input is +

  • Reading/Writing

    NOTE that care must be taken when using them to ensure that safe input is provided; the Trace class ensures safe I/O, low-level I/O functions do not -necessarily ensure safety.

    1. read_word, read_two_words, read_four_words, and read_data

      Functions to read one-, two-, and four-word variables (depending on the header) -and an arbitrary amount of binary data (exclusive to data1 and data2).

    2. convert_to_word, convert_to_words, and bool_to_word

      Takes objects and converts them into std::vector<char> (convert_to_word and -bool_to_word) or std::array<char, N> (convert_to_words, N = # of words).

    3. write_words

      Writes input words (as std::vector<char>) to a binary SAC-file.

  • Utility
    1. concat_words

      Concatenates words taking into account the system endianness.

    2. bits_string and string_bits

      Template function that performs conversion of binary strings of arbitrary length -to an arbitrary number of words.

    3. remove_leading_spaces and remove_trailing_spaces

      Remove leading and trailing blank spaces from strings assuming ASCII convention +necessarily ensure safety.

      1. read_word, read_two_words, read_four_words, and read_data

        Functions to read one-, two-, and four-word variables (depending on the header) +and an arbitrary amount of binary data (exclusive to data1 and data2).

      2. convert_to_word, convert_to_words, and bool_to_word

        Takes objects and converts them into std::vector<char> (convert_to_word and +bool_to_word) or std::array<char, N> (convert_to_words, N = # of words).

      3. write_words

        Writes input words (as std::vector<char>) to a binary SAC-file.

    4. Utility
      1. concat_words

        Concatenates words taking into account the system endianness.

      2. bits_string and string_bits

        Template function that performs conversion of binary strings of arbitrary length +to an arbitrary number of words.

      3. remove_leading_spaces and remove_trailing_spaces

        Remove leading and trailing blank spaces from strings assuming ASCII convention (space character is integer 32, below that value are control characters that -also appear as blank spaces).

      4. string_cleaning

        Ensures string does not contain an internal termination character (\0) and -removes it if present, then removes blank spaces.

      5. prep_string

        Performs string_cleaning followed by string truncation/padding to the necessary -length.

      6. equal_within_tolerance

        Floating-point/double-precision equality within a provided tolerance (default is -f_eps, defined in sac_format.hpp).

  • 3.4. Testing

    utests.cpp contains the unit- and integration-tests, using Catch2. Test coverage +also appear as blank spaces).

  • string_cleaning

    Ensures string does not contain an internal termination character (\0) and +removes it if present, then removes blank spaces.

  • prep_string

    Performs string_cleaning followed by string truncation/padding to the necessary +length.

  • equal_within_tolerance

    Floating-point/double-precision equality within a provided tolerance (default is +f_eps, defined in sac_format.hpp).

  • 3.4. Testing

    utests.cpp contains the unit- and integration-tests, using Catch2. Test coverage details are visible on CodeCov.io and Codacy.com. All tests can be locally-run -to ensure full functionality and compliance.

    3.4.1. Errors only

    By default utests prints out a pass summary, without details unless an error is -encountered.

    3.4.2. Full output

    By passing the --success flag (utests --success) you can see the full results of -all tests.

    3.4.3. Compact output

    The full output is verbose, using the compact reporter will condense the test -results (utests --reporter=compact --success).

    3.4.4. Additional options

    To see additional options, run utests -?.

    3.4.5. Using ctest

    If you have CMake install, you can run the tests using ctest.

    3.5. Benchmarking

    benchmark.cpp contains the benchmarks. Running it locally will provide +to ensure full functionality and compliance.

    3.4.1. Errors only

    By default utests prints out a pass summary, without details unless an error is +encountered.

    3.4.2. Full output

    By passing the --success flag (utests --success) you can see the full results of +all tests.

    3.4.3. Compact output

    The full output is verbose, using the compact reporter will condense the test +results (utests --reporter=compact --success).

    3.4.4. Additional options

    To see additional options, run utests -?.

    3.4.5. Using ctest

    If you have CMake install, you can run the tests using ctest.

    3.5. Benchmarking

    benchmark.cpp contains the benchmarks. Running it locally will provide information on how long each function takes; benchmarks start with the low-level -I/O function and build up to Trace reading, writing, and equality comparison.

    To view available optional flags, run becnhmark -?.

    3.6. Source File List

    3.6.1. Core

    The two core files are split in the standard interface (hpp)/implementation -(cpp) format.

    1. sac_format.hpp

      Interface—function declarations and constants.

    2. sac_format.cpp

      Implementation—function details.

    3.6.2. Testing and Benchmarking

    1. util.hpp

      Utility functions and constants exclusive to testing and benchmarking. Not -split into interface/implementation.

    2. utests.cpp
    3. benchmark.cpp

    3.6.3. Example programs

    1. list_sac.cpp

    3.7. Dependencies

    3.7.1. Automatic (CMake)

    1. Xoshiro-cpp v1.12.0 (testing and benchmarking)
    2. Catch2 v3.4.0 (testing and benchmarking)

    3.8. SAC-file format

    The official and up-to-date documentation for the SAC-file format is available +I/O function and build up to Trace reading, writing, and equality comparison.

    To view available optional flags, run becnhmark -?.

    3.6. Source File List

    3.6.1. Core

    The two core files are split in the standard interface (hpp)/implementation +(cpp) format.

    1. sac_format.hpp

      Interface—function declarations and constants.

    2. sac_format.cpp

      Implementation—function details.

    3.6.2. Testing and Benchmarking

    1. util.hpp

      Utility functions and constants exclusive to testing and benchmarking. Not +split into interface/implementation.

    2. utests.cpp
    3. benchmark.cpp

    3.6.3. Example programs

    1. list_sac.cpp

    3.7. Dependencies

    3.7.1. Automatic (CMake)

    1. Xoshiro-cpp v1.12.0 (testing and benchmarking)
    2. Catch2 v3.4.0 (testing and benchmarking)

    3.8. SAC-file format

    The official and up-to-date documentation for the SAC-file format is available from the EarthScope Consortium (formerly IRIS/UNAVCO) here. The following subsections constitute my notes on the format. Below is a quick guide—all credit for the creation of, and documentation for, the SAC file-format belongs -to its developers and maintainers (details here).

    3.8.1. Floating-point (39)

    32-bit (1 word, 4 bytes)

    1. depmin

      Minimum value of the dependent variable -(displacement/velocity/acceleration/volts/counts).

    2. depmen

      Mean value of the dependent variable.

    3. depmax

      Maximum value of the dependent variable.

    4. odelta

      Modified (observational) value of delta.

    5. resp(0--9)

      Instrument response parameters (poles, zeros, and a constant).

      Not used by SAC—they’re free for other purposes.

    6. stel

      Station elevation in meters above sea level (m.a.s.l).

      Not used by SAC—free for other purposes.

    7. stdp

      Station depth in meters below surface (borehole/buried vault).

      Not used by SAC—free for other purposes.

    8. evel

      Event elevation m.a.s.l.

      Not used by SAC—free for other purposes.

    9. evdp

      Event depth in kilometers (previously meters) below surface.

    10. mag

      Event magnitude.

    11. user(0--9)

      Storage for user-defined values.

    12. dist

      Station–Event distance in kilometers.

    13. az

      Azimuth \(\mathrm{\left(Event \to Station\right)}\), decimal degrees from North.

    14. baz

      Back-azimuth \(\mathrm{\left(Station \to Event\right)}\), decimal degrees from -North.

    15. gcarc

      Station–Event great circle arc-length, decimal degrees.

    16. cmpaz

      Instrument measurement azimuth, decimal degrees from North.
      ValueDirection
      North
      90°East
      180°South
      270°West
      Other1/2/3

    17. cmpinc

      Instrument measurement incident angle, decimal degrees from upward vertical +to its developers and maintainers (details here).

      3.8.1. Floating-point (39)

      32-bit (1 word, 4 bytes)

      1. depmin

        Minimum value of the dependent variable +(displacement/velocity/acceleration/volts/counts).

      2. depmen

        Mean value of the dependent variable.

      3. depmax

        Maximum value of the dependent variable.

      4. odelta

        Modified (observational) value of delta.

      5. resp(0--9)

        Instrument response parameters (poles, zeros, and a constant).

        Not used by SAC—they’re free for other purposes.

      6. stel

        Station elevation in meters above sea level (m.a.s.l).

        Not used by SAC—free for other purposes.

      7. stdp

        Station depth in meters below surface (borehole/buried vault).

        Not used by SAC—free for other purposes.

      8. evel

        Event elevation m.a.s.l.

        Not used by SAC—free for other purposes.

      9. evdp

        Event depth in kilometers (previously meters) below surface.

      10. mag

        Event magnitude.

      11. user(0--9)

        Storage for user-defined values.

      12. dist

        Station–Event distance in kilometers.

      13. az

        Azimuth \(\mathrm{\left(Event \to Station\right)}\), decimal degrees from North.

      14. baz

        Back-azimuth \(\mathrm{\left(Station \to Event\right)}\), decimal degrees from +North.

      15. gcarc

        Station–Event great circle arc-length, decimal degrees.

      16. cmpaz

        Instrument measurement azimuth, decimal degrees from North.
        ValueDirection
        North
        90°East
        180°South
        270°West
        Other1/2/3

      17. cmpinc

        Instrument measurement incident angle, decimal degrees from upward vertical (incident 0° = dip -90°).
        ValueDirection
        Up
        90°Horizontal
        180°Down
        270°Horizontal

        NOTE: SEED/MINISEED use dip angle, decimal degrees down from horizontal (dip -0° = incident 90°).

      18. xminimum

        Spectral-only equivalent of depmin (\(f_{0}\) or \(\omega_{0}\)).

      19. xmaximum

        Spectral-only equivalent of depmax (\(f_{max}\) or \(\omega_{max}\)).

      20. yminimum

        Spectral-only equivalent of b.

      21. ymaximum

        Spectral-only equivalent of e.

      3.8.2. Double (22)

      64-bit (2 words, 8 bytes)

      NOTE: in the header section these are floats—they’re doubles in the footer +0° = incident 90°).

    18. xminimum

      Spectral-only equivalent of depmin (\(f_{0}\) or \(\omega_{0}\)).

    19. xmaximum

      Spectral-only equivalent of depmax (\(f_{max}\) or \(\omega_{max}\)).

    20. yminimum

      Spectral-only equivalent of b.

    21. ymaximum

      Spectral-only equivalent of e.

    3.8.2. Double (22)

    64-bit (2 words, 8 bytes)

    NOTE: in the header section these are floats—they’re doubles in the footer section of v7 SAC-files. In memory they’re stored as doubles regardless of the -SAC-file version.

    1. delta

      Increment between evenly spaced samples (\(\Delta t\) for timeseries, \(\Delta f\) -or \(\Delta\omega\) for spectra).

    2. b

      First value (begin) of independent variable (\(t_{0}\)).

    3. e

      Final value (end) of independent variable (\(t_{max}\)).

    4. o

      Event origin time, in seconds relative to the reference time.

    5. a

      Event first arrival time, in seconds relative to the reference time.

    6. t(0--9)

      User defined time values, in seconds relative to the reference time.

    7. f

      Event end (fini) time, in seconds relative to the reference time.

    8. stla

      Station latitude in decimal degrees, N/S–positive/negative.

      sac-format automatically enforces \(\mathrm{stla}\in[-90, 90]\).

    9. stlo

      Station longitude in decimal degrees, E/W–positive/negative.

      sac-format automatically enforces \(\mathrm{stlo}\in[-180, 180]\).

    10. evla

      Event latitude in decimal degrees, N/S–positive/negative.

      sac-format automatically enforces \(\mathrm{evla}\in[-90, 90]\).

    11. evlo

      Event longitude in decimal degrees, E/W–positive/negative.

      sac-format automatically enforces \(\mathrm{evlo}\in[-180, 180]\).

    12. sb

      Original (saved) b value.

    13. sdelta

      Original (saved) delta value.

    3.8.3. Integer (26)

    32-bit (1 word, 4 bytes)

    1. nzyear

      Reference time GMT year.

    2. nzjday

      Reference time GMT day-of-year (often called Julian Date) (1–366).

    3. nzhour

      Reference time GMT hour (00–23).

    4. nzmin

      Reference time GMT minute (0–59).

    5. nzsec

      Reference time GMT second (0–59).

    6. nzmsec

      Reference time GMT Millisecond (0–999).

    7. nvhdr

      SAC-file version.
      VersionDescription
      v7Footer (2020+, sac 102.0+)
      v6No footer (pre-2020, sac 101.6a-)

    8. norid

      Origin ID.

    9. nevid

      Event ID.

    10. npts

      Number of points in data.

    11. nsnpts

      Original (saved) npts.

    12. nwfid

      Waveform ID.

    13. nxsize

      Spectral-only equivalent of npts (length of spectrum).

    14. nysize

      Spectral-only, width of spectrum.

    15. iftype

      File type.
      ValueTypeDescription
      01ITIMETime-series
      02IRLIMSpectral (real/imaginary)
      03IAMPHSpectral (amplitude/phase)
      04IXYGeneral XY file
      ??IXYZ∗General XYZ file

      ∗Value not listed in the standard.

    16. idep

      Dependent variable type.
      ValueTypeDescription
      05IUNKNUnknown
      06IDISPDisplacement (nm)
      07IVELVelocity \(\mathrm{\left(\frac{nm}{s}\right)}\)
      08IACCAcceleration \(\mathrm{\left(\frac{nm}{s^{2}}\right)}\)
      50IVOLTSVelocity (volts)

    17. iztype

      Reference time equivalent.
      ValueTypeDescription
      05IUNKNUnknown
      09IBRecording start time
      10IDAYMidnight reference GMT day
      11IOEvent origin time
      12IAFirst arrival time
      13–22IT(0–9)User defined time (t) pick

    18. iinst

      Recording instrument type.

      Not used by SAC—free for other purposes.

    19. istreg

      Station geographic region.

      Not used by SAC—free for other purposes.

    20. ievreg

      Event geographic region.

      Not used by SAC—free for other purposes.

    21. ievtyp

      Event type.
      ValueTypeDescription
      05IUNKNUnknown
      11IOOther source of known origin
      37INUCLNuclear
      38IPRENNuclear pre-shot
      39IPOSTNNuclear post-shot
      40IQUAKEEarthquake
      41IPREQForeshock
      42IPOSTQAftershock
      43ICHEMChemical explosion
      44IOTHEROther
      72IQBQuarry/mine blast—confirmed by quarry/mine
      73IQB1Quarry/mine blast—designed shot info-ripple fired
      74IQB2Quarry/mine blast—observed shot info-ripple fired
      75IQBXQuarry/mine blast—single shot
      76IQMTQuarry/mining induced events—tremor and rockbursts
      77IEQEarthquake
      78IEQ1Earthquake in a swarm or in an aftershock sequence
      79IEQ2Felt earthquake
      80IMEMarine explosion
      81IEXOther explosion
      82INUNuclear explosion
      83INCNuclear cavity collapse
      85ILLocal event of unknown origin
      86IRRegion event of unknown origin
      87ITTeleseismic event of unknown origin
      88IUUndetermined/conflicting information

    22. iqual

      Quality of data.
      ValueTypeDescription
      44IOTHEROther
      45IGOODGood
      46IGLCHGlitches
      47IDROPDropouts
      48ILOWSNLow signal-to-noise ratio

      Not used by SAC—free for other purposes.

    23. isynth

      Synthetic data flag.
      ValueTypeDescription
      49IRLDATAReal data
      XXSynthetic

      ∗Values and types not listed in the standard.

    24. imagtyp

      Magnitude type.
      ValueTypeDescription
      52IMBBody-wave magnitude (\(M_{b}\))
      53IMSSurface-wave magnitude (\(M_{s}\))
      54IMLLocal magnitude (\(M_{l}\))
      55IMWMoment magnitude (\(M_{w}\))
      56IMDDuration magnitude (\(M_{d}\))
      57IMXUser-defined magnitude (\(M_{x}\))

    25. imagsrc

      Source of magnitude information.
      ValueTypeDescription
      58INEICNational Earthquake Information Center
      61IPDEPreliminary Determination of Epicenter
      62IISCInternation Seismological Centre
      63IREBReviewed Event Bulletin
      64IUSGSU.S. Geological Survey
      65IBRKUC Berkeley
      66ICALTECHCalifornia Institute of Technology
      67ILLNLLawrence Livermore National Laboratory
      68IEVLOCEvent location (computer program)
      69IJSOPJoint Seismic Observation Program
      70IUSERThe user
      71IUNKNOWNUnknown

    26. ibody

      Body/spheroid definition used to calculate distances.
      ValueTypeNameSemi-major axis (a [m])Inverse Flattening (f)
      -12345UNDEFEarth (Historic)6378160.00.00335293
      98ISUNSun696000000.08.189e-6
      99IMERCURYMercury2439700.00.0
      100IVENUSVenus6051800.00.0
      101IEARTHEarth (WGS84)6378137.00.0033528106647474805
      102IMOONMoon1737400.00.0
      103IMARSMars3396190.00.005886007555525457

    3.8.4. Boolean (4)

    32-bit (1 word, 4 bytes) in-file/8-bit (1 byte) in-memory

    1. leven

      REQUIRED

      Evenly-spaced data flag.

      If true, then data is evenly spaced.

    2. lpspol

      Station polarity flag.

      If true, then station has positive-polarity—it follows the left-hand -convention (for example, North-East-Up [NEZ]).

    3. lovrok

      File overwrite flag.

      If true, then it’s okay to overwrite the file.

    4. lcalda

      Calculate geometry flag.

      If true, then calculate dist, az, baz, and gcarc from stla, stlo, -evla, and evlo.

    3.8.5. String (23)

    32/64-bit (2/4 words, 8/16 bytes, 8/16 characters)

    1. kstnm

      Station name.

    2. kevnm

      Event name.

      ∗This is the only four word (16 character) string.

    3. khole

      Nuclear—hole identifier.

      Other—Location identifier (LOCID).

    4. ko

      Text for o.

    5. ka

      Text for a.

    6. kt(0--9)

      Text for t(0--9).

    7. kf

      Text for f.

    8. kuser(0--2)

      Text for the first three of user(0--9).

    9. kdatrd

      Date the data was read onto a computer.

    10. kinst

      Text for iinst.

    3.8.6. Data (2)

    32-bit (2 words, 8 bytes) in-file/64-bit (4 words, 16 bytes) in-memory

    Stored as floating-point (32-bit) values in SAC-files; stored as -double-precision in memory.

    1. data1

      The first data vector---always present in a SAC-file and begins at word 158.

    2. data2

      The second data vector---conditionally present and begins after data1.

      Required if leven is false, or if iftype is spectral/XY/XYZ.

    4. Notes

    4.1. Why C++20 and not C++23

    Compiler restrictions—C++23 support requires GCC-13+ and Clang-16+. Many +SAC-file version.

    1. delta

      Increment between evenly spaced samples (\(\Delta t\) for timeseries, \(\Delta f\) +or \(\Delta\omega\) for spectra).

    2. b

      First value (begin) of independent variable (\(t_{0}\)).

    3. e

      Final value (end) of independent variable (\(t_{max}\)).

    4. o

      Event origin time, in seconds relative to the reference time.

    5. a

      Event first arrival time, in seconds relative to the reference time.

    6. t(0--9)

      User defined time values, in seconds relative to the reference time.

    7. f

      Event end (fini) time, in seconds relative to the reference time.

    8. stla

      Station latitude in decimal degrees, N/S–positive/negative.

      sac-format automatically enforces \(\mathrm{stla}\in[-90, 90]\).

    9. stlo

      Station longitude in decimal degrees, E/W–positive/negative.

      sac-format automatically enforces \(\mathrm{stlo}\in[-180, 180]\).

    10. evla

      Event latitude in decimal degrees, N/S–positive/negative.

      sac-format automatically enforces \(\mathrm{evla}\in[-90, 90]\).

    11. evlo

      Event longitude in decimal degrees, E/W–positive/negative.

      sac-format automatically enforces \(\mathrm{evlo}\in[-180, 180]\).

    12. sb

      Original (saved) b value.

    13. sdelta

      Original (saved) delta value.

    3.8.3. Integer (26)

    32-bit (1 word, 4 bytes)

    1. nzyear

      Reference time GMT year.

    2. nzjday

      Reference time GMT day-of-year (often called Julian Date) (1–366).

    3. nzhour

      Reference time GMT hour (00–23).

    4. nzmin

      Reference time GMT minute (0–59).

    5. nzsec

      Reference time GMT second (0–59).

    6. nzmsec

      Reference time GMT Millisecond (0–999).

    7. nvhdr

      SAC-file version.
      VersionDescription
      v7Footer (2020+, sac 102.0+)
      v6No footer (pre-2020, sac 101.6a-)

    8. norid

      Origin ID.

    9. nevid

      Event ID.

    10. npts

      Number of points in data.

    11. nsnpts

      Original (saved) npts.

    12. nwfid

      Waveform ID.

    13. nxsize

      Spectral-only equivalent of npts (length of spectrum).

    14. nysize

      Spectral-only, width of spectrum.

    15. iftype

      File type.
      ValueTypeDescription
      01ITIMETime-series
      02IRLIMSpectral (real/imaginary)
      03IAMPHSpectral (amplitude/phase)
      04IXYGeneral XY file
      ??IXYZ∗General XYZ file

      ∗Value not listed in the standard.

    16. idep

      Dependent variable type.
      ValueTypeDescription
      05IUNKNUnknown
      06IDISPDisplacement (nm)
      07IVELVelocity \(\mathrm{\left(\frac{nm}{s}\right)}\)
      08IACCAcceleration \(\mathrm{\left(\frac{nm}{s^{2}}\right)}\)
      50IVOLTSVelocity (volts)

    17. iztype

      Reference time equivalent.
      ValueTypeDescription
      05IUNKNUnknown
      09IBRecording start time
      10IDAYMidnight reference GMT day
      11IOEvent origin time
      12IAFirst arrival time
      13–22IT(0–9)User defined time (t) pick

    18. iinst

      Recording instrument type.

      Not used by SAC—free for other purposes.

    19. istreg

      Station geographic region.

      Not used by SAC—free for other purposes.

    20. ievreg

      Event geographic region.

      Not used by SAC—free for other purposes.

    21. ievtyp

      Event type.
      ValueTypeDescription
      05IUNKNUnknown
      11IOOther source of known origin
      37INUCLNuclear
      38IPRENNuclear pre-shot
      39IPOSTNNuclear post-shot
      40IQUAKEEarthquake
      41IPREQForeshock
      42IPOSTQAftershock
      43ICHEMChemical explosion
      44IOTHEROther
      72IQBQuarry/mine blast—confirmed by quarry/mine
      73IQB1Quarry/mine blast—designed shot info-ripple fired
      74IQB2Quarry/mine blast—observed shot info-ripple fired
      75IQBXQuarry/mine blast—single shot
      76IQMTQuarry/mining induced events—tremor and rockbursts
      77IEQEarthquake
      78IEQ1Earthquake in a swarm or in an aftershock sequence
      79IEQ2Felt earthquake
      80IMEMarine explosion
      81IEXOther explosion
      82INUNuclear explosion
      83INCNuclear cavity collapse
      85ILLocal event of unknown origin
      86IRRegion event of unknown origin
      87ITTeleseismic event of unknown origin
      88IUUndetermined/conflicting information

    22. iqual

      Quality of data.
      ValueTypeDescription
      44IOTHEROther
      45IGOODGood
      46IGLCHGlitches
      47IDROPDropouts
      48ILOWSNLow signal-to-noise ratio

      Not used by SAC—free for other purposes.

    23. isynth

      Synthetic data flag.
      ValueTypeDescription
      49IRLDATAReal data
      XXSynthetic

      ∗Values and types not listed in the standard.

    24. imagtyp

      Magnitude type.
      ValueTypeDescription
      52IMBBody-wave magnitude (\(M_{b}\))
      53IMSSurface-wave magnitude (\(M_{s}\))
      54IMLLocal magnitude (\(M_{l}\))
      55IMWMoment magnitude (\(M_{w}\))
      56IMDDuration magnitude (\(M_{d}\))
      57IMXUser-defined magnitude (\(M_{x}\))

    25. imagsrc

      Source of magnitude information.
      ValueTypeDescription
      58INEICNational Earthquake Information Center
      61IPDEPreliminary Determination of Epicenter
      62IISCInternation Seismological Centre
      63IREBReviewed Event Bulletin
      64IUSGSU.S. Geological Survey
      65IBRKUC Berkeley
      66ICALTECHCalifornia Institute of Technology
      67ILLNLLawrence Livermore National Laboratory
      68IEVLOCEvent location (computer program)
      69IJSOPJoint Seismic Observation Program
      70IUSERThe user
      71IUNKNOWNUnknown

    26. ibody

      Body/spheroid definition used to calculate distances.
      ValueTypeNameSemi-major axis (a [m])Inverse Flattening (f)
      -12345UNDEFEarth (Historic)6378160.00.00335293
      98ISUNSun696000000.08.189e-6
      99IMERCURYMercury2439700.00.0
      100IVENUSVenus6051800.00.0
      101IEARTHEarth (WGS84)6378137.00.0033528106647474805
      102IMOONMoon1737400.00.0
      103IMARSMars3396190.00.005886007555525457

    3.8.4. Boolean (4)

    32-bit (1 word, 4 bytes) in-file/8-bit (1 byte) in-memory

    1. leven

      REQUIRED

      Evenly-spaced data flag.

      If true, then data is evenly spaced.

    2. lpspol

      Station polarity flag.

      If true, then station has positive-polarity—it follows the left-hand +convention (for example, North-East-Up [NEZ]).

    3. lovrok

      File overwrite flag.

      If true, then it’s okay to overwrite the file.

    4. lcalda

      Calculate geometry flag.

      If true, then calculate dist, az, baz, and gcarc from stla, stlo, +evla, and evlo.

    3.8.5. String (23)

    32/64-bit (2/4 words, 8/16 bytes, 8/16 characters)

    1. kstnm

      Station name.

    2. kevnm

      Event name.

      ∗This is the only four word (16 character) string.

    3. khole

      Nuclear—hole identifier.

      Other—Location identifier (LOCID).

    4. ko

      Text for o.

    5. ka

      Text for a.

    6. kt(0--9)

      Text for t(0--9).

    7. kf

      Text for f.

    8. kuser(0--2)

      Text for the first three of user(0--9).

    9. kdatrd

      Date the data was read onto a computer.

    10. kinst

      Text for iinst.

    3.8.6. Data (2)

    32-bit (2 words, 8 bytes) in-file/64-bit (4 words, 16 bytes) in-memory

    Stored as floating-point (32-bit) values in SAC-files; stored as +double-precision in memory.

    1. data1

      The first data vector---always present in a SAC-file and begins at word 158.

    2. data2

      The second data vector---conditionally present and begins after data1.

      Required if leven is false, or if iftype is spectral/XY/XYZ.

    4. Notes

    4.1. Why C++20 and not C++23

    Compiler restrictions—C++23 support requires GCC-13+ and Clang-16+. Many systems, still use GCC-12 and Clang-15—which has near complete support for C++20.

    sac-format strives for accessibility, modernity, safety, and speed—C++20 provides the best fit.

    Author: Alexander R. Blanchette

    Validate

    \ No newline at end of file diff --git a/docs/sac-format_manual.pdf b/docs/sac-format_manual.pdf index decbdc4..fd0c917 100644 Binary files a/docs/sac-format_manual.pdf and b/docs/sac-format_manual.pdf differ diff --git a/get_coverage.sh b/get_coverage.sh index 8ad54cd..e402607 100755 --- a/get_coverage.sh +++ b/get_coverage.sh @@ -8,7 +8,7 @@ fi if [ -e "$base/build/debug/gcc-coverage" ]; then rm -rf "$base/build/debug/gcc-coverage" fi -## Build the preset +# Build the preset cmake --preset gcc-coverage cmake --build build/debug/gcc-coverage # Run my unit tests diff --git a/notes.org b/notes.org index da1f8a7..37ff345 100644 --- a/notes.org +++ b/notes.org @@ -1,8 +1,15 @@ * Inbox ** [2023-11-21 Tue 12:16] Running clang-tidy locally prior to GitHub -~clang-tidy --checks="bugprone-a*,bugprone-b*,bugprone-c*,bugprone-d*,bugprone-em*,bugprone-ex*,bugprone-f*,bugprone-i*,bugprone-l*,bugprone-m*,bugprone-n*,bugprone-o*,bugprone-p*,bugprone-r*,bugprone-s*,bugprone-t*,bugprone-u*,bugprone-v*,performance-*,readability-a*,readability-b*,readability-c*,readability-d*,readability-e*,readability-f*,readability-i*,readability-m*,readability-n*,readability-o*,readability-q*,readability-r*,readability-si*,readability-st*,readability-u*,portability-*,clang-analyzer-*,cppcoreguidelines-avoid-ca*,cpp-coreguidelines-avoid-co*,cpp-coreguidelines-avoid-d*,cpp-coreguidelines-avoid-g*,cpp-coreguidelines-avoid-n*,cpp-coreguidelines-avoid-r*,cpp-coreguidelines-i*,cpp-coreguidelines-m*,cpp-coreguidelines-n*,cpp-coreguidelines-o*,cpp-coreguidelines-pr*,cpp-coreguidelines-pro-bounds-p*,cpp-coreguidelines-pro-t*,cpp-coreguidelines-r*,cpp-coreguidelines-s*,cpp-coreguidelines-v*" --extra-arg="-std=c++20" -p ./compile_commands.json src/sac_format.cpp~ ** [2023-11-21 Tue 10:16] Prior to =git add -A= be sure to run =clang-format= on all *.cpp and *.hpp files! ~clang-format -style=file -i src/sac_format.cpp~ + +** Alternative check + +*NOTE* excluding: modernize-use-trailing-return-type because trailing return + types are silly. Just use type function() {}, instead of auto function -> type + {}. + +~clang-tidy --checks="bugprone-*,performance-*,readability-*,portability-*,clang-analyzer-*,cpp-coreguidelines-*,modernize-a*,modernize-c*,modernize-d*,modernize-l*,modernize-m*,modernize-p*,modernize-r*,modernize-s*,modernize-t*,modernize-un*,modernize-use-a*,modernize-use-b*,modernize-use-c*,modernize-use-d*,modernize-use-e*,modernize-use-n*,modernize-use-o*,modernize-use-s*,modernize-use-tran*,modernize-use-u*" --extra-arg="-std=c++20" -p ./compile_commands.json src/sac_format.cpp~ diff --git a/src/docs/index.org b/src/docs/index.org index f1e8f38..3e343f8 100644 --- a/src/docs/index.org +++ b/src/docs/index.org @@ -31,6 +31,10 @@ CodeFactor + +Coverity Scan Build Status + + CPP-Linter Results @@ -103,9 +107,10 @@ documentation and in-code comments. sac-format is *transparent*---all analysis and coverage information is publicly available online. -- [[https://www.codefactor.io/repository/github/arbcoding/sac-format][CodeFactor Analysis]] -- [[https://app.codacy.com/gh/arbCoding/sac-format/dashboard][Codacy Analysis]] -- [[https://app.codecov.io/gh/arbCoding/sac-format][CodeCov Coverage Analysis]] +- [[https://www.codefactor.io/repository/github/arbcoding/sac-format][CodeFactor]] +- [[https://app.codacy.com/gh/arbCoding/sac-format/dashboard][Codacy]] +- [[https://app.codecov.io/gh/arbCoding/sac-format][CodeCov Coverage]] +- [[https://scan.coverity.com/projects/arbcoding-sac-format][Coverty Scan]] *** Trace Class @@ -309,7 +314,7 @@ using circular symmetry. Limited to $[-180, 180]$ degrees, input that is outside that range is reduced using circular symmetry. -***** Require for safety +***** Required for safety Rules here are required by the SAC format standard. sac-format automatically imposes these rules to prevent the creation of corrupt sac-files. diff --git a/src/sac_format.cpp b/src/sac_format.cpp index 024a812..f647316 100644 --- a/src/sac_format.cpp +++ b/src/sac_format.cpp @@ -7,7 +7,7 @@ namespace sacfmt { //----------------------------------------------------------------------------- // Conversions //----------------------------------------------------------------------------- -int word_position(const int word_number) noexcept { +size_t word_position(const size_t word_number) noexcept { return (word_number * word_length); } @@ -165,21 +165,22 @@ word_one bool_to_binary(const bool flag) noexcept { bool binary_to_bool(const word_one &flag) noexcept { return flag[0]; } -word_two concat_words(const word_one &word1, const word_one &word2) noexcept { +word_two concat_words(const word_pair &pair_words) noexcept { word_two result{}; for (size_t i{0}; i < binary_word_size; ++i) [[likely]] { - result[i] = word1[i]; - result[i + binary_word_size] = word2[i]; + result[i] = pair_words.first[i]; + result[i + binary_word_size] = pair_words.second[i]; } return result; } -word_four concat_words(const word_two &word12, - const word_two &word34) noexcept { +word_four concat_words(const word_pair &pair_words) noexcept { word_four result{}; - for (int i{0}; i < 2 * binary_word_size; ++i) { - result[i] = word12[i]; - result[i + (2 * binary_word_size)] = word34[i]; + for (size_t i{0}; i < static_cast(2) * binary_word_size; ++i) + [[likely]] { + result[i] = pair_words.first[i]; + result[i + (static_cast(2) * binary_word_size)] = + pair_words.second[i]; } return result; } @@ -190,50 +191,60 @@ word_one read_word(std::ifstream *sac) noexcept { word_one bits{}; constexpr size_t char_size{bits_per_byte}; // Where we will store the characters - // flawfinder: ignore - char word[word_length]; + std::array word{}; // Read to our character array + // This can always hold the source due to careful typing/sizing // flawfinder: ignore - sac->read(word, word_length); - // Take each character - std::bitset byte{}; - for (size_t i{0}; i < word_length; ++i) [[likely]] { - size_t character{static_cast(word[i])}; - byte = std::bitset(character); - // bit-by-bit - for (size_t j{0}; j < char_size; ++j) [[likely]] { - bits[(i * char_size) + j] = byte[j]; + if (sac->read(word.data(), word_length)) { + // Take each character + std::bitset byte{}; + for (size_t i{0}; i < word_length; ++i) [[likely]] { + size_t character{static_cast(word[i])}; + byte = std::bitset(character); + // bit-by-bit + for (size_t j{0}; j < char_size; ++j) [[likely]] { + bits[(i * char_size) + j] = byte[j]; + } } } return bits; } word_two read_two_words(std::ifstream *sac) noexcept { - word_one word1{read_word(sac)}; - word_one word2{read_word(sac)}; + const word_one first_word{read_word(sac)}; + const word_one second_word{read_word(sac)}; + word_pair pair_words{}; if constexpr (std::endian::native == std::endian::little) { - return concat_words(word1, word2); + pair_words.first = first_word; + pair_words.second = second_word; } else { - return concat_words(word2, word1); + pair_words.first = second_word; + pair_words.second = first_word; } + return concat_words(pair_words); } word_four read_four_words(std::ifstream *sac) noexcept { - word_two word12{read_two_words(sac)}; - word_two word34{read_two_words(sac)}; + const word_two first_words{read_two_words(sac)}; + const word_two second_words{read_two_words(sac)}; + word_pair pair_words{}; if constexpr (std::endian::native == std::endian::little) { - return concat_words(word12, word34); + pair_words.first = first_words; + pair_words.second = second_words; } else { - return concat_words(word34, word12); + pair_words.first = second_words; + pair_words.second = first_words; } + return concat_words(pair_words); } -std::vector read_data(std::ifstream *sac, const size_t n_words, - const int start) noexcept { - sac->seekg(word_position(start)); +std::vector read_data(std::ifstream *sac, + const read_spec &spec) noexcept { + // static_cast is safe because I'm never using negative values + sac->seekg(static_cast(word_position(spec.start_word))); std::vector result{}; - result.resize(n_words); - for (size_t i{0}; i < n_words; ++i) [[likely]] { + result.resize(spec.num_words); + for (size_t i{0}; i < spec.num_words; ++i) [[likely]] { result[i] = static_cast(binary_to_float(read_word(sac))); } return result; @@ -253,11 +264,10 @@ void write_words(std::ofstream *sac_file, const std::vector &input) { // Template on the typename to make possible to handle float or int template std::vector convert_to_word(const T input) noexcept { - // flawfinder: ignore - char tmp[word_length]; + std::array tmp{}; // Copy bytes from input into the tmp array // flawfinder: ignore - std::memcpy(tmp, &input, word_length); + std::memcpy(tmp.data(), &input, word_length); std::vector word{}; word.resize(word_length); for (int i{0}; i < word_length; ++i) [[likely]] { @@ -271,11 +281,10 @@ template std::vector convert_to_word(const float input) noexcept; template std::vector convert_to_word(const int x) noexcept; std::vector convert_to_word(const double input) noexcept { - // flawfinder: ignore - char tmp[2 * word_length]; + std::array(2) * word_length> tmp{}; // Copy bytes from input into the tmp array // flawfinder: ignore - std::memcpy(tmp, &input, static_cast(2) * word_length); + std::memcpy(tmp.data(), &input, static_cast(2) * word_length); std::vector word{}; word.resize(static_cast(2) * word_length); for (int i{0}; i < 2 * word_length; ++i) { @@ -1138,31 +1147,32 @@ void Trace::resize_data(const size_t size) noexcept { } //------------------------------------------------------------------------------ // Read -bool nwords_after_current(std::ifstream *sac, const size_t current_pos, - const size_t n_words) noexcept { +bool nwords_after_current(std::ifstream *sac, const read_spec &spec) noexcept { bool result{false}; if (sac->good()) { sac->seekg(0, std::ios::end); const std::size_t final_pos{static_cast(sac->tellg())}; // Doesn't like size_t since it wants to allow // the possibility of negative offsets (not how I use it) - sac->seekg(static_cast(current_pos)); - const std::size_t diff{final_pos - current_pos}; - result = (diff >= (n_words * word_length)); + sac->seekg(static_cast(spec.start_word)); + const std::size_t diff{final_pos - spec.start_word}; + result = (diff >= (spec.num_words * word_length)); } return result; } void safe_to_read_header(std::ifstream *sac) { - if (!nwords_after_current(sac, 0, data_word)) { + const read_spec spec{data_word, 0}; + if (!nwords_after_current(sac, spec)) { throw io_error("Insufficient filesize for header."); } } void safe_to_read_footer(std::ifstream *sac) { // doubles are two words long - if (!nwords_after_current(sac, sac->tellg(), - static_cast(num_footer) * 2)) { + const read_spec spec{static_cast(num_footer) * 2, + static_cast(sac->tellg())}; + if (!nwords_after_current(sac, spec)) { throw io_error("Insufficient filesize for footer."); } } @@ -1170,7 +1180,8 @@ void safe_to_read_footer(std::ifstream *sac) { void safe_to_read_data(std::ifstream *sac, const size_t n_words, const bool data2) { const std::string data{data2 ? "data2" : "data1"}; - if (!nwords_after_current(sac, sac->tellg(), n_words)) { + const read_spec spec{n_words, static_cast(sac->tellg())}; + if (!nwords_after_current(sac, spec)) { throw io_error("Insufficient filesize for " + data + '.'); } } @@ -1349,18 +1360,20 @@ Trace::Trace(const std::filesystem::path &path) { // DATA const bool is_data{npts() != unset_int}; // data1 - const size_t npts_s{static_cast(npts())}; + const size_t n_words{static_cast(npts())}; if (is_data) { // false flags for data1 - safe_to_read_data(&file, npts_s, false); // throws io_error if unsafe + safe_to_read_data(&file, n_words, false); // throws io_error if unsafe + const read_spec spec{n_words, data_word}; // Originally floats, read as doubles - data1(read_data(&file, npts_s, data_word)); + data1(read_data(&file, spec)); } // data2 (uneven or spectral data) if (is_data && (!leven() || (iftype() > 1))) { // true flags for data2 - safe_to_read_data(&file, npts_s, true); // throws io_error if unsafe - data2(read_data(&file, npts_s, data_word + npts())); + safe_to_read_data(&file, n_words, true); // throws io_error if unsafe + const read_spec spec{n_words, data_word + npts()}; + data2(read_data(&file, spec)); } //-------------------------------------------------------------------------- // Footer diff --git a/src/sac_format.hpp b/src/sac_format.hpp index 830c68b..51cb89b 100644 --- a/src/sac_format.hpp +++ b/src/sac_format.hpp @@ -32,6 +32,8 @@ #include // std::unordered_map #include +// std::move +#include // std::vector #include @@ -45,7 +47,7 @@ constexpr int bits_per_byte{8}; // binary character size // Each word is 32-bits (4 bytes) constexpr int binary_word_size{word_length * bits_per_byte}; // First word of (first) data-section -constexpr int data_word{158}; +constexpr size_t data_word{158}; constexpr int unset_int{-12345}; constexpr float unset_float{-12345.0F}; constexpr double unset_double{-12345.0}; @@ -80,7 +82,7 @@ constexpr double earth_radius{6378.14}; // km // Conversions //-------------------------------------------------------------------------- // Calculate position of word in SAC-file -int word_position(int word_number) noexcept; +size_t word_position(size_t word_number) noexcept; // SAC uses 32 bit ints word_one int_to_binary(int num) noexcept; int binary_to_int(word_one bin) noexcept; @@ -136,19 +138,30 @@ std::string binary_to_long_string(const word_four &str) noexcept; word_one bool_to_binary(bool flag) noexcept; bool binary_to_bool(const word_one &flag) noexcept; // Concat words +// Struct allay bugprone similar types warning on concat_words +template struct word_pair { + T first{}; + T second{}; +}; // For some reason, template functions didn't want to work for these... -word_two concat_words(const word_one &word1, const word_one &word2) noexcept; -word_four concat_words(const word_two &word12, const word_two &word34) noexcept; +word_two concat_words(const word_pair &pair_words) noexcept; +word_four concat_words(const word_pair &pair_words) noexcept; //-------------------------------------------------------------------------- // Reading //-------------------------------------------------------------------------- +// Struct to allay clang-tidy bugprone swappable parameters warning +struct read_spec { + // cppcheck-suppress unusedStructMember + size_t num_words{}; + // cppcheck-suppress unusedStructMember + size_t start_word{}; +}; // The below functions make reading SAFE and prevent exceptions when // trying to read a file without a massive performance hit, unless // you try to use it for every single word (see how it is chunk-checked // in Trace::Trace to see an efficient/intuitive scheme) // Does the filesize remaining fit n_words? -bool nwords_after_current(std::ifstream *sac, size_t current_pos, - size_t n_words) noexcept; +bool nwords_after_current(std::ifstream *sac, const read_spec &spec) noexcept; // Does the filesize fit the header? void safe_to_read_header(std::ifstream *sac); // Does the remaining filesize fit the footer? @@ -168,8 +181,8 @@ word_two read_two_words(std::ifstream *sac) noexcept; word_four read_four_words(std::ifstream *sac) noexcept; // Can read any number of words into a vector of doubles // Useful for data values -std::vector read_data(std::ifstream *sac, size_t n_words, - int start = data_word) noexcept; +std::vector read_data(std::ifstream *sac, + const read_spec &spec) noexcept; //-------------------------------------------------------------------------- // Writing //-------------------------------------------------------------------------- @@ -473,132 +486,132 @@ class Trace { bool operator==(const Trace &other) const noexcept; // Convenience functions void calc_geometry() noexcept; - double frequency() const noexcept; - std::string date() const noexcept; - std::string time() const noexcept; + [[nodiscard]] double frequency() const noexcept; + [[nodiscard]] std::string date() const noexcept; + [[nodiscard]] std::string time() const noexcept; // Getters // Floats - float depmin() const noexcept; - float depmax() const noexcept; - float odelta() const noexcept; - float resp0() const noexcept; - float resp1() const noexcept; - float resp2() const noexcept; - float resp3() const noexcept; - float resp4() const noexcept; - float resp5() const noexcept; - float resp6() const noexcept; - float resp7() const noexcept; - float resp8() const noexcept; - float resp9() const noexcept; - float stel() const noexcept; - float stdp() const noexcept; - float evel() const noexcept; - float evdp() const noexcept; - float mag() const noexcept; - float user0() const noexcept; - float user1() const noexcept; - float user2() const noexcept; - float user3() const noexcept; - float user4() const noexcept; - float user5() const noexcept; - float user6() const noexcept; - float user7() const noexcept; - float user8() const noexcept; - float user9() const noexcept; - float dist() const noexcept; - float az() const noexcept; - float baz() const noexcept; - float gcarc() const noexcept; - float depmen() const noexcept; - float cmpaz() const noexcept; - float cmpinc() const noexcept; - float xminimum() const noexcept; - float xmaximum() const noexcept; - float yminimum() const noexcept; - float ymaximum() const noexcept; + [[nodiscard]] float depmin() const noexcept; + [[nodiscard]] float depmax() const noexcept; + [[nodiscard]] float odelta() const noexcept; + [[nodiscard]] float resp0() const noexcept; + [[nodiscard]] float resp1() const noexcept; + [[nodiscard]] float resp2() const noexcept; + [[nodiscard]] float resp3() const noexcept; + [[nodiscard]] float resp4() const noexcept; + [[nodiscard]] float resp5() const noexcept; + [[nodiscard]] float resp6() const noexcept; + [[nodiscard]] float resp7() const noexcept; + [[nodiscard]] float resp8() const noexcept; + [[nodiscard]] float resp9() const noexcept; + [[nodiscard]] float stel() const noexcept; + [[nodiscard]] float stdp() const noexcept; + [[nodiscard]] float evel() const noexcept; + [[nodiscard]] float evdp() const noexcept; + [[nodiscard]] float mag() const noexcept; + [[nodiscard]] float user0() const noexcept; + [[nodiscard]] float user1() const noexcept; + [[nodiscard]] float user2() const noexcept; + [[nodiscard]] float user3() const noexcept; + [[nodiscard]] float user4() const noexcept; + [[nodiscard]] float user5() const noexcept; + [[nodiscard]] float user6() const noexcept; + [[nodiscard]] float user7() const noexcept; + [[nodiscard]] float user8() const noexcept; + [[nodiscard]] float user9() const noexcept; + [[nodiscard]] float dist() const noexcept; + [[nodiscard]] float az() const noexcept; + [[nodiscard]] float baz() const noexcept; + [[nodiscard]] float gcarc() const noexcept; + [[nodiscard]] float depmen() const noexcept; + [[nodiscard]] float cmpaz() const noexcept; + [[nodiscard]] float cmpinc() const noexcept; + [[nodiscard]] float xminimum() const noexcept; + [[nodiscard]] float xmaximum() const noexcept; + [[nodiscard]] float yminimum() const noexcept; + [[nodiscard]] float ymaximum() const noexcept; // Doubles - double delta() const noexcept; - double b() const noexcept; - double e() const noexcept; - double o() const noexcept; - double a() const noexcept; - double t0() const noexcept; - double t1() const noexcept; - double t2() const noexcept; - double t3() const noexcept; - double t4() const noexcept; - double t5() const noexcept; - double t6() const noexcept; - double t7() const noexcept; - double t8() const noexcept; - double t9() const noexcept; - double f() const noexcept; - double stla() const noexcept; - double stlo() const noexcept; - double evla() const noexcept; - double evlo() const noexcept; - double sb() const noexcept; - double sdelta() const noexcept; + [[nodiscard]] double delta() const noexcept; + [[nodiscard]] double b() const noexcept; + [[nodiscard]] double e() const noexcept; + [[nodiscard]] double o() const noexcept; + [[nodiscard]] double a() const noexcept; + [[nodiscard]] double t0() const noexcept; + [[nodiscard]] double t1() const noexcept; + [[nodiscard]] double t2() const noexcept; + [[nodiscard]] double t3() const noexcept; + [[nodiscard]] double t4() const noexcept; + [[nodiscard]] double t5() const noexcept; + [[nodiscard]] double t6() const noexcept; + [[nodiscard]] double t7() const noexcept; + [[nodiscard]] double t8() const noexcept; + [[nodiscard]] double t9() const noexcept; + [[nodiscard]] double f() const noexcept; + [[nodiscard]] double stla() const noexcept; + [[nodiscard]] double stlo() const noexcept; + [[nodiscard]] double evla() const noexcept; + [[nodiscard]] double evlo() const noexcept; + [[nodiscard]] double sb() const noexcept; + [[nodiscard]] double sdelta() const noexcept; // Ints - int nzyear() const noexcept; - int nzjday() const noexcept; - int nzhour() const noexcept; - int nzmin() const noexcept; - int nzsec() const noexcept; - int nzmsec() const noexcept; - int nvhdr() const noexcept; - int norid() const noexcept; - int nevid() const noexcept; - int npts() const noexcept; - int nsnpts() const noexcept; - int nwfid() const noexcept; - int nxsize() const noexcept; - int nysize() const noexcept; - int iftype() const noexcept; - int idep() const noexcept; - int iztype() const noexcept; - int iinst() const noexcept; - int istreg() const noexcept; - int ievreg() const noexcept; - int ievtyp() const noexcept; - int iqual() const noexcept; - int isynth() const noexcept; - int imagtyp() const noexcept; - int imagsrc() const noexcept; - int ibody() const noexcept; + [[nodiscard]] int nzyear() const noexcept; + [[nodiscard]] int nzjday() const noexcept; + [[nodiscard]] int nzhour() const noexcept; + [[nodiscard]] int nzmin() const noexcept; + [[nodiscard]] int nzsec() const noexcept; + [[nodiscard]] int nzmsec() const noexcept; + [[nodiscard]] int nvhdr() const noexcept; + [[nodiscard]] int norid() const noexcept; + [[nodiscard]] int nevid() const noexcept; + [[nodiscard]] int npts() const noexcept; + [[nodiscard]] int nsnpts() const noexcept; + [[nodiscard]] int nwfid() const noexcept; + [[nodiscard]] int nxsize() const noexcept; + [[nodiscard]] int nysize() const noexcept; + [[nodiscard]] int iftype() const noexcept; + [[nodiscard]] int idep() const noexcept; + [[nodiscard]] int iztype() const noexcept; + [[nodiscard]] int iinst() const noexcept; + [[nodiscard]] int istreg() const noexcept; + [[nodiscard]] int ievreg() const noexcept; + [[nodiscard]] int ievtyp() const noexcept; + [[nodiscard]] int iqual() const noexcept; + [[nodiscard]] int isynth() const noexcept; + [[nodiscard]] int imagtyp() const noexcept; + [[nodiscard]] int imagsrc() const noexcept; + [[nodiscard]] int ibody() const noexcept; // Bools - bool leven() const noexcept; - bool lpspol() const noexcept; - bool lovrok() const noexcept; - bool lcalda() const noexcept; + [[nodiscard]] bool leven() const noexcept; + [[nodiscard]] bool lpspol() const noexcept; + [[nodiscard]] bool lovrok() const noexcept; + [[nodiscard]] bool lcalda() const noexcept; // Strings - std::string kstnm() const noexcept; - std::string kevnm() const noexcept; - std::string khole() const noexcept; - std::string ko() const noexcept; - std::string ka() const noexcept; - std::string kt0() const noexcept; - std::string kt1() const noexcept; - std::string kt2() const noexcept; - std::string kt3() const noexcept; - std::string kt4() const noexcept; - std::string kt5() const noexcept; - std::string kt6() const noexcept; - std::string kt7() const noexcept; - std::string kt8() const noexcept; - std::string kt9() const noexcept; - std::string kf() const noexcept; - std::string kuser0() const noexcept; - std::string kuser1() const noexcept; - std::string kuser2() const noexcept; - std::string kcmpnm() const noexcept; - std::string knetwk() const noexcept; - std::string kdatrd() const noexcept; - std::string kinst() const noexcept; + [[nodiscard]] std::string kstnm() const noexcept; + [[nodiscard]] std::string kevnm() const noexcept; + [[nodiscard]] std::string khole() const noexcept; + [[nodiscard]] std::string ko() const noexcept; + [[nodiscard]] std::string ka() const noexcept; + [[nodiscard]] std::string kt0() const noexcept; + [[nodiscard]] std::string kt1() const noexcept; + [[nodiscard]] std::string kt2() const noexcept; + [[nodiscard]] std::string kt3() const noexcept; + [[nodiscard]] std::string kt4() const noexcept; + [[nodiscard]] std::string kt5() const noexcept; + [[nodiscard]] std::string kt6() const noexcept; + [[nodiscard]] std::string kt7() const noexcept; + [[nodiscard]] std::string kt8() const noexcept; + [[nodiscard]] std::string kt9() const noexcept; + [[nodiscard]] std::string kf() const noexcept; + [[nodiscard]] std::string kuser0() const noexcept; + [[nodiscard]] std::string kuser1() const noexcept; + [[nodiscard]] std::string kuser2() const noexcept; + [[nodiscard]] std::string kcmpnm() const noexcept; + [[nodiscard]] std::string knetwk() const noexcept; + [[nodiscard]] std::string kdatrd() const noexcept; + [[nodiscard]] std::string kinst() const noexcept; // Data - std::vector data1() const noexcept; - std::vector data2() const noexcept; + [[nodiscard]] std::vector data1() const noexcept; + [[nodiscard]] std::vector data2() const noexcept; // Setters // Floats void depmin(float input) noexcept; @@ -736,7 +749,7 @@ class Trace { void calc_dist() noexcept; void calc_az() noexcept; void calc_baz() noexcept; - bool geometry_set() const noexcept; + [[nodiscard]] bool geometry_set() const noexcept; void resize_data1(size_t size) noexcept; void resize_data2(size_t size) noexcept; void resize_data(size_t size) noexcept; @@ -760,8 +773,10 @@ class io_error : public std::exception { const std::string message{}; public: - explicit io_error(const std::string &msg) : message(msg) {} - const char *what() const noexcept { return message.c_str(); } + explicit io_error(std::string msg) : message(std::move(msg)) {} + [[nodiscard]] const char *what() const noexcept override { + return message.c_str(); + } }; }; // namespace sacfmt #endif diff --git a/todo.org b/todo.org index 31210ae..cf1ec1a 100644 --- a/todo.org +++ b/todo.org @@ -57,7 +57,12 @@ leven(false) and iftype(<1), but data2 exists, clear it. ***** TODO Read in ***** TODO Write out *** TODO Support Big-Endian sac-files (currently only little-endian) - +*** TODO Provide functions to update dependent parameters +**** TODO xminimum/xmaximum +**** TODO yminimum/ymaximum +**** TODO depmin/depmen/depmax +*** TODO String setters should be limited in length +Same rules apply as for the strings themselves. ** DONE Refactor Trace :refactor: *** DONE Remove boost dependency The only reason I need boost is for boost::algorithm::trim(); to remove leading