From 536e3112f56070d78b45e5fdb41435290fbedb64 Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@tu-dortmund.de>
Date: Mon, 25 Jan 2021 21:05:22 +0100
Subject: [PATCH] CLI tool with docopt as dependency

---
 .gitignore                |  1 +
 .gitmodules               |  3 ++
 CMakeLists.txt            | 22 ++++++++++++--
 external/docopt.cpp       |  1 +
 src/RunningStatistics.cpp |  2 +-
 src/rstat.cpp             | 64 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 90 insertions(+), 3 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 .gitmodules
 create mode 160000 external/docopt.cpp
 create mode 100644 src/rstat.cpp

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..7b40909
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "external/docopt.cpp"]
+	path = external/docopt.cpp
+	url = https://github.com/docopt/docopt.cpp.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 13bf3d0..2e114c9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,17 +1,35 @@
 cmake_minimum_required(VERSION 3.17)
 
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
 project(librstat VERSION 1.0 LANGUAGES CXX)
 
 add_library(rstat SHARED src/RunningStatistics.cpp)
+add_library(rstatStatic STATIC src/RunningStatistics.cpp)
+
+add_subdirectory(external/docopt.cpp)
+
+add_executable(rstatExe src/rstat.cpp)
 
 find_package(GSL 2.4 REQUIRED)
+#find_package(docopt COMPONENTS CXX REQUIRED)
 
-target_include_directories(rstat PRIVATE include)
+target_include_directories(rstat PUBLIC include)
 target_link_libraries(rstat GSL::gsl GSL::gslcblas)
 
+target_link_libraries(rstatExe rstat docopt)
+
+target_include_directories(rstatStatic PRIVATE include)
+target_link_libraries(rstatStatic GSL::gsl GSL::gslcblas)
+
 set_target_properties(rstat PROPERTIES PUBLIC_HEADER include/RunningStatistics.hpp)
+set_target_properties(rstatStatic PROPERTIES PUBLIC_HEADER include/RunningStatistics.hpp)
+set_target_properties(rstatStatic PROPERTIES OUTPUT_NAME rstat)
+set_target_properties(rstatExe PROPERTIES OUTPUT_NAME rstat)
 
 include(GNUInstallDirs)
-install(TARGETS rstat
+install(TARGETS rstat rstatStatic rstatExe
   LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
   PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/external/docopt.cpp b/external/docopt.cpp
new file mode 160000
index 0000000..6f5de76
--- /dev/null
+++ b/external/docopt.cpp
@@ -0,0 +1 @@
+Subproject commit 6f5de76970be94a6f1e4556d1716593100e285d2
diff --git a/src/RunningStatistics.cpp b/src/RunningStatistics.cpp
index a039704..ee50413 100644
--- a/src/RunningStatistics.cpp
+++ b/src/RunningStatistics.cpp
@@ -20,7 +20,7 @@
 
 #include <gsl/gsl_rstat.h>
 
-#include "RunningStatistics.hpp"
+#include <RunningStatistics.hpp>
 
 RunningStatistics::RunningStatistics()
 {
diff --git a/src/rstat.cpp b/src/rstat.cpp
new file mode 100644
index 0000000..9dfa486
--- /dev/null
+++ b/src/rstat.cpp
@@ -0,0 +1,64 @@
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cstdlib>
+#include <string>
+
+#include "RunningStatistics.hpp"
+
+//#define DOCOPT_HEADER_ONLY
+#include <docopt.h>
+
+static const char USAGE[] =
+R"(Usage: rstat [options] FILE
+
+Options:
+  -m, --mean            print mean
+  -o, --stddev-mean     print standard deviation of mean
+  -s, --stddev          print standard deviation
+  -v, --variance        print variance
+  -n, --numsamples      print number of samples
+  --min                 print minimum
+  --max                 print maximum
+  --precision=<digits>  number of digits to print [default: 5]
+)";
+
+int main(int argc, char** argv) {
+  std::map<std::string, docopt::value> args = docopt::docopt(USAGE,
+    { argv + 1, argv + argc }, true, "rstat 0.1");
+
+  std::string const filename = args["FILE"].asString() == "-"? "/dev/stdin" : args["FILE"].asString();
+  std::ifstream input(filename);
+
+  auto digits = args["--precision"].asLong();
+
+  RunningStatistics statistics;
+
+  for (double v; input >> v;)
+  {
+    statistics.add(v);
+  }
+
+  if (auto a = args["--numsamples"]; a && a.asBool())
+    std::cout << "samples: " << std::setw(digits) << statistics.n() << std::endl;
+
+  if (auto a = args["--mean"]; a && a.asBool())
+    std::cout << "mean: " << std::setw(digits) << statistics.mean() << std::endl;
+  
+  if (auto a = args["--stddev-mean"]; a && a.asBool())
+    std::cout << "std. dev. mean: " << std::setw(digits) << statistics.std_dev_mean() << std::endl;
+
+  if (auto a = args["--stddev"]; a && a.asBool())
+    std::cout << "std. dev.: " << std::setw(digits) << statistics.std_dev() << std::endl;
+
+  if (auto a = args["--variance"]; a && a.asBool())
+    std::cout << "variance: " << std::setw(digits) << statistics.variance() << std::endl;
+
+  if (auto a = args["--min"]; a && a.asBool())
+    std::cout << "minimum: " << std::setw(digits) << statistics.min() << std::endl;
+
+  if (auto a = args["--max"]; a && a.asBool())
+    std::cout << "maximum: " << std::setw(digits) << statistics.max() << std::endl;
+
+  return EXIT_SUCCESS;
+}
-- 
GitLab