diff --git a/.gitignore b/.gitignore index 2f28caf..7f42aa0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,3 @@ raytracer # Actual output image image.ppm - -# Profiler data -perf.* - -# Core dumps -core diff --git a/Makefile b/Makefile index c983530..22930b9 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,12 @@ INCLUDE=./include LIBS=-pthread -lm -FLAGS=-Ofast -march=native -g -Wall -Wextra -Wpedantic +FLAGS=-Og -g -Wall -Wextra -Wpedantic -raytracer: camera.hpp color.hpp hittable.hpp hittable_list.hpp main.cpp material.hpp random.h ray.hpp rtweekend.hpp sphere.hpp vec3.hpp $(INCLUDE)/Remotery.c $(INCLUDE)/Remotery.h - g++ $(FLAGS) -I$(INCLUDE) $(LIBS) main.cpp -o raytracer - -make debug: +raytracer: camera.hpp color.hpp hittable.hpp hittable_list.hpp main.cpp material.hpp ray.hpp rtweekend.hpp sphere.hpp vec3.hpp $(INCLUDE)/Remotery.c $(INCLUDE)/Remotery.h + @g++ $(FLAGS) -I$(INCLUDE) $(LIBS) main.cpp -o raytracer image: raytracer - @./raytracer -o image.ppm + @./raytracer > image.ppm @if [ $$TERM = "xterm-kitty" ]; then\ kitty icat image.ppm;\ fi diff --git a/camera.hpp b/camera.hpp index 5de6d7d..970ffad 100644 --- a/camera.hpp +++ b/camera.hpp @@ -10,21 +10,21 @@ struct camera { vec3 horizontal; vec3 vertical; vec3 u,v,w; - float lens_radius; + double lens_radius; /* Constructors */ camera(point3 lookfrom, point3 lookat, vec3 vup, - float vfov, - float aspect_ratio, - float aperture, - float focus_dist) + double vfov, + double aspect_ratio, + double aperture, + double focus_dist) { - float theta = degrees_to_radians(vfov); - float h = tan(theta/2); - float viewport_height = 2.0 * h; - float viewport_width = aspect_ratio * viewport_height; + double theta = degrees_to_radians(vfov); + double h = tan(theta/2); + double viewport_height = 2.0 * h; + double viewport_width = aspect_ratio * viewport_height; w = normalize(lookfrom - lookat); u = normalize(cross(vup,w)); @@ -40,9 +40,10 @@ struct camera { /* Methods */ - ray get_ray(float s, float t, int32_t thread_id = 0) const - { - vec3 rd = lens_radius * random_in_unit_disk(thread_id); + ray get_ray(double s, double t) const + { + rmt_ScopedCPUSample(GetRay, RMTSF_Aggregate); + vec3 rd = lens_radius * random_in_unit_disk(); vec3 offset = u * rd.x + v * rd.y; return ray(origin + offset, lower_left_corner + s*horizontal + t*vertical - origin - offset); diff --git a/color.hpp b/color.hpp index 3f940a6..ca38d1f 100644 --- a/color.hpp +++ b/color.hpp @@ -9,12 +9,12 @@ /* Writes color components as a space-delimited string of numbers in the range [0,255] */ void write_color(FILE *fp, color c, uint32_t samples_per_pixel) { - float scale = 1.0 / samples_per_pixel; + double scale = 1.0 / samples_per_pixel; // Divide the color by the number of samples - float r = sqrt(c.x * scale); - float g = sqrt(c.y * scale); - float b = sqrt(c.z * scale); + double r = sqrt(c.x * scale); + double g = sqrt(c.y * scale); + double b = sqrt(c.z * scale); /* Write output */ fprintf(fp, @@ -24,12 +24,4 @@ void write_color(FILE *fp, color c, uint32_t samples_per_pixel) (uint8_t) (255 * clamp(b, 0, 1))); } -void write_image(color *image, uint64_t n, FILE *fp, uint32_t samples_per_pixel) -{ - for (int64_t i = n-1; i >= 0; --i) - { - write_color(fp, image[i], samples_per_pixel); - } -} - #endif diff --git a/hittable.hpp b/hittable.hpp index 7edb7c9..6baef66 100644 --- a/hittable.hpp +++ b/hittable.hpp @@ -6,7 +6,7 @@ /* Virtual class that represents objects who could collide against a ray */ struct hittable { - virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const = 0; + virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const = 0; }; #endif diff --git a/hittable_list.hpp b/hittable_list.hpp index 9c3366e..3a1416b 100644 --- a/hittable_list.hpp +++ b/hittable_list.hpp @@ -2,7 +2,6 @@ #define HITTABLE_LIST_H #include "hittable.hpp" -#include "sphere.hpp" #include #include @@ -10,34 +9,30 @@ using std::shared_ptr; using std::make_shared; -template -struct hittable_list { +struct hittable_list : hittable { /* Attributes */ - std::vector objects; + std::vector> objects; /* Constructors */ hittable_list () {} - hittable_list(T object) { add(object); } + hittable_list(shared_ptr h) { add(h); } /* Methods */ void clear() { objects.clear(); } - void add (T h) { objects.push_back(h); } + void add (shared_ptr h) { objects.push_back(h); } - bool hit(const ray& r, float t_min, float t_max, hit_record& rec); + virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const override; }; -template -bool hittable_list::hit(const ray& r, float t_min, float t_max, hit_record& rec) +bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const { rmt_ScopedCPUSample(HittableList_Hit, RMTSF_Aggregate); hit_record temp_rec; bool hit_anything = false; - float closest_so_far = t_max; + double closest_so_far = t_max; - uint32_t s = objects.size(); - for (uint32_t i = 0; i < s; ++i) + for (const auto& object : objects) { - T *object = &objects[i]; if (object->hit(r, t_min, closest_so_far, temp_rec)) { hit_anything = true; diff --git a/include/indicators.hpp b/include/indicators.hpp deleted file mode 100644 index 46a0f05..0000000 --- a/include/indicators.hpp +++ /dev/null @@ -1,4649 +0,0 @@ - -#ifndef INDICATORS_COLOR -#define INDICATORS_COLOR - -namespace indicators { -enum class Color { grey, red, green, yellow, blue, magenta, cyan, white, unspecified }; -} - -#endif - - - -#ifndef INDICATORS_FONT_STYLE -#define INDICATORS_FONT_STYLE - -namespace indicators { -enum class FontStyle { bold, dark, italic, underline, blink, reverse, concealed, crossed }; -} - -#endif - - - -#ifndef INDICATORS_PROGRESS_TYPE -#define INDICATORS_PROGRESS_TYPE - -namespace indicators { -enum class ProgressType { incremental, decremental }; -} - -#endif - -//! -//! termcolor -//! ~~~~~~~~~ -//! -//! termcolor is a header-only c++ library for printing colored messages -//! to the terminal. Written just for fun with a help of the Force. -//! -//! :copyright: (c) 2013 by Ihor Kalnytskyi -//! :license: BSD, see LICENSE for details -//! - -#ifndef TERMCOLOR_HPP_ -#define TERMCOLOR_HPP_ - -#include -#include - -// Detect target's platform and set some macros in order to wrap platform -// specific code this library depends on. -#if defined(_WIN32) || defined(_WIN64) -# define TERMCOLOR_TARGET_WINDOWS -#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) -# define TERMCOLOR_TARGET_POSIX -#endif - -// If implementation has not been explicitly set, try to choose one based on -// target platform. -#if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) -# if defined(TERMCOLOR_TARGET_POSIX) -# define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# elif defined(TERMCOLOR_TARGET_WINDOWS) -# define TERMCOLOR_USE_WINDOWS_API -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# endif -#endif - -// These headers provide isatty()/fileno() functions, which are used for -// testing whether a standard stream refers to the terminal. -#if defined(TERMCOLOR_TARGET_POSIX) -# include -#elif defined(TERMCOLOR_TARGET_WINDOWS) -#if defined(_MSC_VER) -#if !defined(NOMINMAX) -#define NOMINMAX -#endif -#endif -# include -# include -#endif - - -namespace termcolor -{ - // Forward declaration of the `_internal` namespace. - // All comments are below. - namespace _internal - { - inline int colorize_index(); - inline FILE* get_standard_stream(const std::ostream& stream); - inline bool is_colorized(std::ostream& stream); - inline bool is_atty(const std::ostream& stream); - - #if defined(TERMCOLOR_TARGET_WINDOWS) - inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); - #endif - } - - inline - std::ostream& colorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 1L; - return stream; - } - - inline - std::ostream& nocolorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 0L; - return stream; - } - - inline - std::ostream& reset(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[00m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, -1); - #endif - } - return stream; - } - - inline - std::ostream& bold(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[1m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& dark(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[2m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& italic(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[3m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& underline(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[4m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); - #endif - } - return stream; - } - - inline - std::ostream& blink(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[5m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& reverse(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[7m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& concealed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[8m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& crossed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[9m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[38;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[48;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[30m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[31m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[32m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[33m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[34m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[35m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[36m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[37m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - - inline - std::ostream& bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[90m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 | FOREGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[91m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[92m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[93m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[94m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[95m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[96m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[97m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - - inline - std::ostream& on_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[40m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[41m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[42m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& on_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[43m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[44m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[45m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[46m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[47m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - - return stream; - } - - - inline - std::ostream& on_bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[100m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 | BACKGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[101m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[102m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[103m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[104m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[105m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[106m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[107m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - - return stream; - } - - - - //! Since C++ hasn't a way to hide something in the header from - //! the outer access, I have to introduce this namespace which - //! is used for internal purpose and should't be access from - //! the user code. - namespace _internal - { - // An index to be used to access a private storage of I/O streams. See - // colorize / nocolorize I/O manipulators for details. Due to the fact - // that static variables ain't shared between translation units, inline - // function with local static variable is used to do the trick and share - // the variable value between translation units. - inline int colorize_index() - { - static int colorize_index = std::ios_base::xalloc(); - return colorize_index; - } - - //! Since C++ hasn't a true way to extract stream handler - //! from the a given `std::ostream` object, I have to write - //! this kind of hack. - inline - FILE* get_standard_stream(const std::ostream& stream) - { - if (&stream == &std::cout) - return stdout; - else if ((&stream == &std::cerr) || (&stream == &std::clog)) - return stderr; - - return nullptr; - } - - // Say whether a given stream should be colorized or not. It's always - // true for ATTY streams and may be true for streams marked with - // colorize flag. - inline - bool is_colorized(std::ostream& stream) - { - return is_atty(stream) || static_cast(stream.iword(colorize_index())); - } - - //! Test whether a given `std::ostream` object refers to - //! a terminal. - inline - bool is_atty(const std::ostream& stream) - { - FILE* std_stream = get_standard_stream(stream); - - // Unfortunately, fileno() ends with segmentation fault - // if invalid file descriptor is passed. So we need to - // handle this case gracefully and assume it's not a tty - // if standard stream is not detected, and 0 is returned. - if (!std_stream) - return false; - - #if defined(TERMCOLOR_TARGET_POSIX) - return ::isatty(fileno(std_stream)); - #elif defined(TERMCOLOR_TARGET_WINDOWS) - return ::_isatty(_fileno(std_stream)); - #else - return false; - #endif - } - - #if defined(TERMCOLOR_TARGET_WINDOWS) - //! Change Windows Terminal colors attribute. If some - //! parameter is `-1` then attribute won't changed. - inline void win_change_attributes(std::ostream& stream, int foreground, int background) - { - // yeah, i know.. it's ugly, it's windows. - static WORD defaultAttributes = 0; - - // Windows doesn't have ANSI escape sequences and so we use special - // API to change Terminal output color. That means we can't - // manipulate colors by means of "std::stringstream" and hence - // should do nothing in this case. - if (!_internal::is_atty(stream)) - return; - - // get terminal handle - HANDLE hTerminal = INVALID_HANDLE_VALUE; - if (&stream == &std::cout) - hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); - else if (&stream == &std::cerr) - hTerminal = GetStdHandle(STD_ERROR_HANDLE); - - // save default terminal attributes if it unsaved - if (!defaultAttributes) - { - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - defaultAttributes = info.wAttributes; - } - - // restore all default settings - if (foreground == -1 && background == -1) - { - SetConsoleTextAttribute(hTerminal, defaultAttributes); - return; - } - - // get current settings - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - - if (foreground != -1) - { - info.wAttributes &= ~(info.wAttributes & 0x0F); - info.wAttributes |= static_cast(foreground); - } - - if (background != -1) - { - info.wAttributes &= ~(info.wAttributes & 0xF0); - info.wAttributes |= static_cast(background); - } - - SetConsoleTextAttribute(hTerminal, info.wAttributes); - } - #endif // TERMCOLOR_TARGET_WINDOWS - - } // namespace _internal - -} // namespace termcolor - - -#undef TERMCOLOR_TARGET_POSIX -#undef TERMCOLOR_TARGET_WINDOWS - -#if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) -# undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# undef TERMCOLOR_USE_WINDOWS_API -#endif - -#endif // TERMCOLOR_HPP_ - - - -#ifndef INDICATORS_TERMINAL_SIZE -#define INDICATORS_TERMINAL_SIZE -#include - - -#if defined(_WIN32) -#include - -namespace indicators { - -static inline std::pair terminal_size() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - int cols, rows; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); - cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; - rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - return {static_cast(rows), static_cast(cols)}; -} - -static inline size_t terminal_width() { return terminal_size().second; } - -} // namespace indicators - -#else - -#include //ioctl() and TIOCGWINSZ -#include // for STDOUT_FILENO - -namespace indicators { - -static inline std::pair terminal_size() { - struct winsize size{}; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &size); - return {static_cast(size.ws_row), static_cast(size.ws_col)}; -} - -static inline size_t terminal_width() { return terminal_size().second; } - -} // namespace indicators - -#endif - -#endif - - -/* -Activity Indicators for Modern C++ -https://github.com/p-ranav/indicators - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2019 Dawid Pilarski . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -#ifndef INDICATORS_SETTING -#define INDICATORS_SETTING - -#include -// #include -#ifndef INDICATORS_COLOR -#define INDICATORS_COLOR - -namespace indicators { -enum class Color { grey, red, green, yellow, blue, magenta, cyan, white, unspecified }; -} - -#endif - -// #include -#ifndef INDICATORS_FONT_STYLE -#define INDICATORS_FONT_STYLE - -namespace indicators { -enum class FontStyle { bold, dark, italic, underline, blink, reverse, concealed, crossed }; -} - -#endif - -// #include -#ifndef INDICATORS_PROGRESS_TYPE -#define INDICATORS_PROGRESS_TYPE - -namespace indicators { -enum class ProgressType { incremental, decremental }; -} - -#endif -#include -#include -#include -#include -#include - -namespace indicators { - -namespace details { - -template struct if_else; - -template <> struct if_else { using type = std::true_type; }; - -template <> struct if_else { using type = std::false_type; }; - -template struct if_else_type; - -template struct if_else_type { - using type = True; -}; - -template struct if_else_type { - using type = False; -}; - -template struct conjuction; - -template <> struct conjuction<> : std::true_type {}; - -template -struct conjuction - : if_else_type>::type {}; - -template struct disjunction; - -template <> struct disjunction<> : std::false_type {}; - -template -struct disjunction - : if_else_type>::type {}; - -enum class ProgressBarOption { - bar_width = 0, - prefix_text, - postfix_text, - start, - end, - fill, - lead, - remainder, - max_postfix_text_len, - completed, - show_percentage, - show_elapsed_time, - show_remaining_time, - saved_start_time, - foreground_color, - spinner_show, - spinner_states, - font_styles, - hide_bar_when_complete, - min_progress, - max_progress, - progress_type, - stream -}; - -template struct Setting { - template ::value>::type> - explicit Setting(Args &&... args) : value(std::forward(args)...) {} - Setting(const Setting &) = default; - Setting(Setting &&) = default; - - static constexpr auto id = Id; - using type = T; - - T value{}; -}; - -template struct is_setting : std::false_type {}; - -template struct is_setting> : std::true_type {}; - -template -struct are_settings : if_else...>::value>::type {}; - -template <> struct are_settings<> : std::true_type {}; - -template struct is_setting_from_tuple; - -template struct is_setting_from_tuple> : std::true_type {}; - -template -struct is_setting_from_tuple> - : if_else...>::value>::type {}; - -template -struct are_settings_from_tuple - : if_else...>::value>::type {}; - -template struct always_true { static constexpr auto value = true; }; - -template Default &&get_impl(Default &&def) { - return std::forward(def); -} - -template -auto get_impl(Default && /*def*/, T &&first, Args &&... /*tail*/) -> - typename std::enable_if<(std::decay::type::id == Id), - decltype(std::forward(first))>::type { - return std::forward(first); -} - -template -auto get_impl(Default &&def, T && /*first*/, Args &&... tail) -> - typename std::enable_if<(std::decay::type::id != Id), - decltype(get_impl(std::forward(def), - std::forward(tail)...))>::type { - return get_impl(std::forward(def), std::forward(tail)...); -} - -template ::value, void>::type> -auto get(Default &&def, Args &&... args) - -> decltype(details::get_impl(std::forward(def), std::forward(args)...)) { - return details::get_impl(std::forward(def), std::forward(args)...); -} - -template using StringSetting = Setting; - -template using IntegerSetting = Setting; - -template using BooleanSetting = Setting; - -template struct option_idx; - -template -struct option_idx, counter> - : if_else_type<(Id == T::id), std::integral_constant, - option_idx, counter + 1>>::type {}; - -template struct option_idx, counter> { - static_assert(always_true<(ProgressBarOption)Id>::value, "No such option was found"); -}; - -template -auto get_value(Settings &&settings) - -> decltype((std::get::type>::value>( - std::declval()))) { - return std::get::type>::value>( - std::forward(settings)); -} - -} // namespace details - -namespace option { -using BarWidth = details::IntegerSetting; -using PrefixText = details::StringSetting; -using PostfixText = details::StringSetting; -using Start = details::StringSetting; -using End = details::StringSetting; -using Fill = details::StringSetting; -using Lead = details::StringSetting; -using Remainder = details::StringSetting; -using MaxPostfixTextLen = details::IntegerSetting; -using Completed = details::BooleanSetting; -using ShowPercentage = details::BooleanSetting; -using ShowElapsedTime = details::BooleanSetting; -using ShowRemainingTime = details::BooleanSetting; -using SavedStartTime = details::BooleanSetting; -using ForegroundColor = details::Setting; -using ShowSpinner = details::BooleanSetting; -using SpinnerStates = - details::Setting, details::ProgressBarOption::spinner_states>; -using HideBarWhenComplete = - details::BooleanSetting; -using FontStyles = - details::Setting, details::ProgressBarOption::font_styles>; -using MinProgress = details::IntegerSetting; -using MaxProgress = details::IntegerSetting; -using ProgressType = details::Setting; -using Stream = details::Setting; -} // namespace option -} // namespace indicators - -#endif - - -#ifndef INDICATORS_CURSOR_CONTROL -#define INDICATORS_CURSOR_CONTROL - -#if defined(_MSC_VER) -#if !defined(NOMINMAX) -#define NOMINMAX -#endif -#include -#include -#else -#include -#endif - -namespace indicators { - -#if defined(_MSC_VER) - -static inline void show_console_cursor(bool const show) { - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); - - CONSOLE_CURSOR_INFO cursorInfo; - - GetConsoleCursorInfo(out, &cursorInfo); - cursorInfo.bVisible = show; // set the cursor visibility - SetConsoleCursorInfo(out, &cursorInfo); -} - -#else - -static inline void show_console_cursor(bool const show) { - std::fputs(show ? "\033[?25h" : "\033[?25l", stdout); -} - -#endif - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_CURSOR_MOVEMENT -#define INDICATORS_CURSOR_MOVEMENT - -#if defined(_MSC_VER) -#if !defined(NOMINMAX) -#define NOMINMAX -#endif -#include -#include -#else -#include -#endif - -namespace indicators { - -#ifdef _MSC_VER - -static inline void move(int x, int y) { - auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - if (!hStdout) - return; - - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - - COORD cursor; - - cursor.X = csbiInfo.dwCursorPosition.X + x; - cursor.Y = csbiInfo.dwCursorPosition.Y + y; - SetConsoleCursorPosition(hStdout, cursor); -} - -static inline void move_up(int lines) { move(0, -lines); } -static inline void move_down(int lines) { move(0, -lines); } -static inline void move_right(int cols) { move(cols, 0); } -static inline void move_left(int cols) { move(-cols, 0); } - -#else - -static inline void move_up(int lines) { std::cout << "\033[" << lines << "A"; } -static inline void move_down(int lines) { std::cout << "\033[" << lines << "B"; } -static inline void move_right(int cols) { std::cout << "\033[" << cols << "C"; } -static inline void move_left(int cols) { std::cout << "\033[" << cols << "D"; } - -#endif - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_STREAM_HELPER -#define INDICATORS_STREAM_HELPER - -// #include -#ifndef INDICATORS_DISPLAY_WIDTH -#define INDICATORS_DISPLAY_WIDTH - -#include -#if __has_include() -#include -#define INDICATORS_HAVE_CODECVT 1 -#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING -#endif -#include -#include -#include -#include - -namespace unicode { - -#if INDICATORS_HAVE_CODECVT -namespace details { - -/* - * This is an implementation of wcwidth() and wcswidth() (defined in - * IEEE Std 1002.1-2001) for Unicode. - * - * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html - * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html - * - * In fixed-width output devices, Latin characters all occupy a single - * "cell" position of equal width, whereas ideographic CJK characters - * occupy two such cells. Interoperability between terminal-line - * applications and (teletype-style) character terminals using the - * UTF-8 encoding requires agreement on which character should advance - * the cursor by how many cell positions. No established formal - * standards exist at present on which Unicode character shall occupy - * how many cell positions on character terminals. These routines are - * a first attempt of defining such behavior based on simple rules - * applied to data provided by the Unicode Consortium. - * - * For some graphical characters, the Unicode standard explicitly - * defines a character-cell width via the definition of the East Asian - * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. - * In all these cases, there is no ambiguity about which width a - * terminal shall use. For characters in the East Asian Ambiguous (A) - * class, the width choice depends purely on a preference of backward - * compatibility with either historic CJK or Western practice. - * Choosing single-width for these characters is easy to justify as - * the appropriate long-term solution, as the CJK practice of - * displaying these characters as double-width comes from historic - * implementation simplicity (8-bit encoded characters were displayed - * single-width and 16-bit ones double-width, even for Greek, - * Cyrillic, etc.) and not any typographic considerations. - * - * Much less clear is the choice of width for the Not East Asian - * (Neutral) class. Existing practice does not dictate a width for any - * of these characters. It would nevertheless make sense - * typographically to allocate two character cells to characters such - * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be - * represented adequately with a single-width glyph. The following - * routines at present merely assign a single-cell width to all - * neutral characters, in the interest of simplicity. This is not - * entirely satisfactory and should be reconsidered before - * establishing a formal standard in this area. At the moment, the - * decision which Not East Asian (Neutral) characters should be - * represented by double-width glyphs cannot yet be answered by - * applying a simple rule from the Unicode database content. Setting - * up a proper standard for the behavior of UTF-8 character terminals - * will require a careful analysis not only of each Unicode character, - * but also of each presentation form, something the author of these - * routines has avoided to do so far. - * - * http://www.unicode.org/unicode/reports/tr11/ - * - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted. The author - * disclaims all warranties with regard to this software. - * - * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ - -struct interval { - int first; - int last; -}; - -/* auxiliary function for binary search in interval table */ -static inline int bisearch(wchar_t ucs, const struct interval *table, int max) { - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} - -/* The following two functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded - * in ISO 10646. - */ - -static inline int mk_wcwidth(wchar_t ucs) { - /* sorted list of non-overlapping intervals of non-spacing characters */ - /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ - static const struct interval combining[] = { - {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, {0x0591, 0x05BD}, - {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, - {0x0600, 0x0603}, {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, - {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x070F, 0x070F}, - {0x0711, 0x0711}, {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, - {0x0901, 0x0902}, {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, - {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, - {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, - {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, - {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, - {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, - {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, - {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, - {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, - {0x0CBC, 0x0CBC}, {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, - {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, - {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, - {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, - {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, - {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, - {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, - {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, - {0x1160, 0x11FF}, {0x135F, 0x135F}, {0x1712, 0x1714}, {0x1732, 0x1734}, - {0x1752, 0x1753}, {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, - {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, {0x180B, 0x180D}, - {0x18A9, 0x18A9}, {0x1920, 0x1922}, {0x1927, 0x1928}, {0x1932, 0x1932}, - {0x1939, 0x193B}, {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, - {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, {0x1B6B, 0x1B73}, - {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, {0x200B, 0x200F}, {0x202A, 0x202E}, - {0x2060, 0x2063}, {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, - {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA825, 0xA826}, - {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, - {0xFFF9, 0xFFFB}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, - {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, {0x1D173, 0x1D182}, - {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, - {0xE0020, 0xE007F}, {0xE0100, 0xE01EF}}; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) - return -1; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1)) - return 0; - - /* if we arrive here, ucs is not a combining or C0/C1 control character */ - - return 1 + (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -} - -static inline int mk_wcswidth(const wchar_t *pwcs, size_t n) { - int w, width = 0; - - for (; *pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} - -/* - * The following functions are the same as mk_wcwidth() and - * mk_wcswidth(), except that spacing characters in the East Asian - * Ambiguous (A) category as defined in Unicode Technical Report #11 - * have a column width of 2. This variant might be useful for users of - * CJK legacy encodings who want to migrate to UCS without changing - * the traditional terminal character-width behaviour. It is not - * otherwise recommended for general use. - */ -static inline int mk_wcwidth_cjk(wchar_t ucs) { - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ - static const struct interval ambiguous[] = { - {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, {0x00AA, 0x00AA}, {0x00AE, 0x00AE}, - {0x00B0, 0x00B4}, {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, {0x00D0, 0x00D0}, - {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, - {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, - {0x0101, 0x0101}, {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, {0x0126, 0x0127}, - {0x012B, 0x012B}, {0x0131, 0x0133}, {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, - {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, {0x0166, 0x0167}, {0x016B, 0x016B}, - {0x01CE, 0x01CE}, {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, {0x01D6, 0x01D6}, - {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, - {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, - {0x02D8, 0x02DB}, {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0391, 0x03A1}, {0x03A3, 0x03A9}, - {0x03B1, 0x03C1}, {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451}, - {0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022}, - {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035}, {0x203B, 0x203B}, - {0x203E, 0x203E}, {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC}, - {0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116}, - {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154}, {0x215B, 0x215E}, - {0x2160, 0x216B}, {0x2170, 0x2179}, {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, - {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203}, {0x2207, 0x2208}, - {0x220B, 0x220B}, {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A}, - {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E}, - {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C}, {0x2252, 0x2252}, - {0x2260, 0x2261}, {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283}, - {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, - {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573}, {0x2580, 0x258F}, - {0x2592, 0x2595}, {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7}, - {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, - {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609}, {0x260E, 0x260F}, - {0x2614, 0x2615}, {0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640}, {0x2642, 0x2642}, - {0x2660, 0x2661}, {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F}, - {0x273D, 0x273D}, {0x2776, 0x277F}, {0xE000, 0xF8FF}, {0xFFFD, 0xFFFD}, {0xF0000, 0xFFFFD}, - {0x100000, 0x10FFFD}}; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) - return 2; - - return mk_wcwidth(ucs); -} - -static inline int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) { - int w, width = 0; - - for (; *pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth_cjk(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} - -// convert UTF-8 string to wstring -static inline std::wstring utf8_decode(const std::string &str) { - std::wstring_convert> myconv; - return myconv.from_bytes(str); -} - -// convert wstring to UTF-8 string -static inline std::string utf8_encode(const std::wstring &str) { - std::wstring_convert> myconv; - return myconv.to_bytes(str); -} - -} // namespace details - -static inline int display_width(const std::string &input) { - using namespace unicode::details; - return mk_wcswidth(utf8_decode(input).c_str(), input.size()); -} - -static inline int display_width(const std::wstring &input) { - return details::mk_wcswidth(input.c_str(), input.size()); -} - -#else - -static inline int display_width(const std::string &input) { - return input.length(); -} - -static inline int display_width(const std::wstring &input) { - return input.length(); -} - -#endif - -} // namespace unicode - -#endif -// #include -/* -Activity Indicators for Modern C++ -https://github.com/p-ranav/indicators - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2019 Dawid Pilarski . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -#ifndef INDICATORS_SETTING -#define INDICATORS_SETTING - -#include -// #include -// #include -// #include -#include -#include -#include -#include -#include - -namespace indicators { - -namespace details { - -template struct if_else; - -template <> struct if_else { using type = std::true_type; }; - -template <> struct if_else { using type = std::false_type; }; - -template struct if_else_type; - -template struct if_else_type { - using type = True; -}; - -template struct if_else_type { - using type = False; -}; - -template struct conjuction; - -template <> struct conjuction<> : std::true_type {}; - -template -struct conjuction - : if_else_type>::type {}; - -template struct disjunction; - -template <> struct disjunction<> : std::false_type {}; - -template -struct disjunction - : if_else_type>::type {}; - -enum class ProgressBarOption { - bar_width = 0, - prefix_text, - postfix_text, - start, - end, - fill, - lead, - remainder, - max_postfix_text_len, - completed, - show_percentage, - show_elapsed_time, - show_remaining_time, - saved_start_time, - foreground_color, - spinner_show, - spinner_states, - font_styles, - hide_bar_when_complete, - min_progress, - max_progress, - progress_type, - stream -}; - -template struct Setting { - template ::value>::type> - explicit Setting(Args &&... args) : value(std::forward(args)...) {} - Setting(const Setting &) = default; - Setting(Setting &&) = default; - - static constexpr auto id = Id; - using type = T; - - T value{}; -}; - -template struct is_setting : std::false_type {}; - -template struct is_setting> : std::true_type {}; - -template -struct are_settings : if_else...>::value>::type {}; - -template <> struct are_settings<> : std::true_type {}; - -template struct is_setting_from_tuple; - -template struct is_setting_from_tuple> : std::true_type {}; - -template -struct is_setting_from_tuple> - : if_else...>::value>::type {}; - -template -struct are_settings_from_tuple - : if_else...>::value>::type {}; - -template struct always_true { static constexpr auto value = true; }; - -template Default &&get_impl(Default &&def) { - return std::forward(def); -} - -template -auto get_impl(Default && /*def*/, T &&first, Args &&... /*tail*/) -> - typename std::enable_if<(std::decay::type::id == Id), - decltype(std::forward(first))>::type { - return std::forward(first); -} - -template -auto get_impl(Default &&def, T && /*first*/, Args &&... tail) -> - typename std::enable_if<(std::decay::type::id != Id), - decltype(get_impl(std::forward(def), - std::forward(tail)...))>::type { - return get_impl(std::forward(def), std::forward(tail)...); -} - -template ::value, void>::type> -auto get(Default &&def, Args &&... args) - -> decltype(details::get_impl(std::forward(def), std::forward(args)...)) { - return details::get_impl(std::forward(def), std::forward(args)...); -} - -template using StringSetting = Setting; - -template using IntegerSetting = Setting; - -template using BooleanSetting = Setting; - -template struct option_idx; - -template -struct option_idx, counter> - : if_else_type<(Id == T::id), std::integral_constant, - option_idx, counter + 1>>::type {}; - -template struct option_idx, counter> { - static_assert(always_true<(ProgressBarOption)Id>::value, "No such option was found"); -}; - -template -auto get_value(Settings &&settings) - -> decltype((std::get::type>::value>( - std::declval()))) { - return std::get::type>::value>( - std::forward(settings)); -} - -} // namespace details - -namespace option { -using BarWidth = details::IntegerSetting; -using PrefixText = details::StringSetting; -using PostfixText = details::StringSetting; -using Start = details::StringSetting; -using End = details::StringSetting; -using Fill = details::StringSetting; -using Lead = details::StringSetting; -using Remainder = details::StringSetting; -using MaxPostfixTextLen = details::IntegerSetting; -using Completed = details::BooleanSetting; -using ShowPercentage = details::BooleanSetting; -using ShowElapsedTime = details::BooleanSetting; -using ShowRemainingTime = details::BooleanSetting; -using SavedStartTime = details::BooleanSetting; -using ForegroundColor = details::Setting; -using ShowSpinner = details::BooleanSetting; -using SpinnerStates = - details::Setting, details::ProgressBarOption::spinner_states>; -using HideBarWhenComplete = - details::BooleanSetting; -using FontStyles = - details::Setting, details::ProgressBarOption::font_styles>; -using MinProgress = details::IntegerSetting; -using MaxProgress = details::IntegerSetting; -using ProgressType = details::Setting; -using Stream = details::Setting; -} // namespace option -} // namespace indicators - -#endif -// #include //! -//! termcolor -//! ~~~~~~~~~ -//! -//! termcolor is a header-only c++ library for printing colored messages -//! to the terminal. Written just for fun with a help of the Force. -//! -//! :copyright: (c) 2013 by Ihor Kalnytskyi -//! :license: BSD, see LICENSE for details -//! - -#ifndef TERMCOLOR_HPP_ -#define TERMCOLOR_HPP_ - -#include -#include - -// Detect target's platform and set some macros in order to wrap platform -// specific code this library depends on. -#if defined(_WIN32) || defined(_WIN64) -# define TERMCOLOR_TARGET_WINDOWS -#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) -# define TERMCOLOR_TARGET_POSIX -#endif - -// If implementation has not been explicitly set, try to choose one based on -// target platform. -#if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) -# if defined(TERMCOLOR_TARGET_POSIX) -# define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# elif defined(TERMCOLOR_TARGET_WINDOWS) -# define TERMCOLOR_USE_WINDOWS_API -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# endif -#endif - -// These headers provide isatty()/fileno() functions, which are used for -// testing whether a standard stream refers to the terminal. -#if defined(TERMCOLOR_TARGET_POSIX) -# include -#elif defined(TERMCOLOR_TARGET_WINDOWS) -#if defined(_MSC_VER) -#if !defined(NOMINMAX) -#define NOMINMAX -#endif -#endif -# include -# include -#endif - - -namespace termcolor -{ - // Forward declaration of the `_internal` namespace. - // All comments are below. - namespace _internal - { - inline int colorize_index(); - inline FILE* get_standard_stream(const std::ostream& stream); - inline bool is_colorized(std::ostream& stream); - inline bool is_atty(const std::ostream& stream); - - #if defined(TERMCOLOR_TARGET_WINDOWS) - inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); - #endif - } - - inline - std::ostream& colorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 1L; - return stream; - } - - inline - std::ostream& nocolorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 0L; - return stream; - } - - inline - std::ostream& reset(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[00m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, -1); - #endif - } - return stream; - } - - inline - std::ostream& bold(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[1m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& dark(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[2m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& italic(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[3m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& underline(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[4m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); - #endif - } - return stream; - } - - inline - std::ostream& blink(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[5m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& reverse(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[7m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& concealed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[8m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& crossed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[9m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[38;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[48;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[30m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[31m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[32m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[33m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[34m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[35m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[36m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[37m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - - inline - std::ostream& bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[90m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 | FOREGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[91m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[92m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[93m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[94m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[95m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[96m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[97m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - - inline - std::ostream& on_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[40m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[41m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[42m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& on_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[43m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[44m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[45m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[46m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[47m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - - return stream; - } - - - inline - std::ostream& on_bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[100m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 | BACKGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[101m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[102m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[103m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[104m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[105m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[106m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[107m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - - return stream; - } - - - - //! Since C++ hasn't a way to hide something in the header from - //! the outer access, I have to introduce this namespace which - //! is used for internal purpose and should't be access from - //! the user code. - namespace _internal - { - // An index to be used to access a private storage of I/O streams. See - // colorize / nocolorize I/O manipulators for details. Due to the fact - // that static variables ain't shared between translation units, inline - // function with local static variable is used to do the trick and share - // the variable value between translation units. - inline int colorize_index() - { - static int colorize_index = std::ios_base::xalloc(); - return colorize_index; - } - - //! Since C++ hasn't a true way to extract stream handler - //! from the a given `std::ostream` object, I have to write - //! this kind of hack. - inline - FILE* get_standard_stream(const std::ostream& stream) - { - if (&stream == &std::cout) - return stdout; - else if ((&stream == &std::cerr) || (&stream == &std::clog)) - return stderr; - - return nullptr; - } - - // Say whether a given stream should be colorized or not. It's always - // true for ATTY streams and may be true for streams marked with - // colorize flag. - inline - bool is_colorized(std::ostream& stream) - { - return is_atty(stream) || static_cast(stream.iword(colorize_index())); - } - - //! Test whether a given `std::ostream` object refers to - //! a terminal. - inline - bool is_atty(const std::ostream& stream) - { - FILE* std_stream = get_standard_stream(stream); - - // Unfortunately, fileno() ends with segmentation fault - // if invalid file descriptor is passed. So we need to - // handle this case gracefully and assume it's not a tty - // if standard stream is not detected, and 0 is returned. - if (!std_stream) - return false; - - #if defined(TERMCOLOR_TARGET_POSIX) - return ::isatty(fileno(std_stream)); - #elif defined(TERMCOLOR_TARGET_WINDOWS) - return ::_isatty(_fileno(std_stream)); - #else - return false; - #endif - } - - #if defined(TERMCOLOR_TARGET_WINDOWS) - //! Change Windows Terminal colors attribute. If some - //! parameter is `-1` then attribute won't changed. - inline void win_change_attributes(std::ostream& stream, int foreground, int background) - { - // yeah, i know.. it's ugly, it's windows. - static WORD defaultAttributes = 0; - - // Windows doesn't have ANSI escape sequences and so we use special - // API to change Terminal output color. That means we can't - // manipulate colors by means of "std::stringstream" and hence - // should do nothing in this case. - if (!_internal::is_atty(stream)) - return; - - // get terminal handle - HANDLE hTerminal = INVALID_HANDLE_VALUE; - if (&stream == &std::cout) - hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); - else if (&stream == &std::cerr) - hTerminal = GetStdHandle(STD_ERROR_HANDLE); - - // save default terminal attributes if it unsaved - if (!defaultAttributes) - { - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - defaultAttributes = info.wAttributes; - } - - // restore all default settings - if (foreground == -1 && background == -1) - { - SetConsoleTextAttribute(hTerminal, defaultAttributes); - return; - } - - // get current settings - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - - if (foreground != -1) - { - info.wAttributes &= ~(info.wAttributes & 0x0F); - info.wAttributes |= static_cast(foreground); - } - - if (background != -1) - { - info.wAttributes &= ~(info.wAttributes & 0xF0); - info.wAttributes |= static_cast(background); - } - - SetConsoleTextAttribute(hTerminal, info.wAttributes); - } - #endif // TERMCOLOR_TARGET_WINDOWS - - } // namespace _internal - -} // namespace termcolor - - -#undef TERMCOLOR_TARGET_POSIX -#undef TERMCOLOR_TARGET_WINDOWS - -#if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) -# undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# undef TERMCOLOR_USE_WINDOWS_API -#endif - -#endif // TERMCOLOR_HPP_ - - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace indicators { -namespace details { - -inline void set_stream_color(std::ostream &os, Color color) { - switch (color) { - case Color::grey: - os << termcolor::grey; - break; - case Color::red: - os << termcolor::red; - break; - case Color::green: - os << termcolor::green; - break; - case Color::yellow: - os << termcolor::yellow; - break; - case Color::blue: - os << termcolor::blue; - break; - case Color::magenta: - os << termcolor::magenta; - break; - case Color::cyan: - os << termcolor::cyan; - break; - case Color::white: - os << termcolor::white; - break; - default: - assert(false); - } -} - -inline void set_font_style(std::ostream &os, FontStyle style) { - switch (style) { - case FontStyle::bold: - os << termcolor::bold; - break; - case FontStyle::dark: - os << termcolor::dark; - break; - case FontStyle::italic: - os << termcolor::italic; - break; - case FontStyle::underline: - os << termcolor::underline; - break; - case FontStyle::blink: - os << termcolor::blink; - break; - case FontStyle::reverse: - os << termcolor::reverse; - break; - case FontStyle::concealed: - os << termcolor::concealed; - break; - case FontStyle::crossed: - os << termcolor::crossed; - break; - default: - break; - } -} - -inline std::ostream &write_duration(std::ostream &os, std::chrono::nanoseconds ns) { - using namespace std; - using namespace std::chrono; - using days = duration>; - char fill = os.fill(); - os.fill('0'); - auto d = duration_cast(ns); - ns -= d; - auto h = duration_cast(ns); - ns -= h; - auto m = duration_cast(ns); - ns -= m; - auto s = duration_cast(ns); - if (d.count() > 0) - os << setw(2) << d.count() << "d:"; - if (h.count() > 0) - os << setw(2) << h.count() << "h:"; - os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's'; - os.fill(fill); - return os; -} - -class BlockProgressScaleWriter { -public: - BlockProgressScaleWriter(std::ostream &os, size_t bar_width) : os(os), bar_width(bar_width) {} - - std::ostream &write(float progress) { - std::string fill_text{"█"}; - std::vector lead_characters{" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}; - auto value = (std::min)(1.0f, (std::max)(0.0f, progress / 100.0f)); - auto whole_width = std::floor(value * bar_width); - auto remainder_width = fmod((value * bar_width), 1.0f); - auto part_width = std::floor(remainder_width * lead_characters.size()); - std::string lead_text = lead_characters[size_t(part_width)]; - if ((bar_width - whole_width - 1) < 0) - lead_text = ""; - for (size_t i = 0; i < whole_width; ++i) - os << fill_text; - os << lead_text; - for (size_t i = 0; i < (bar_width - whole_width - 1); ++i) - os << " "; - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; -}; - -class ProgressScaleWriter { -public: - ProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill, - const std::string &lead, const std::string &remainder) - : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {} - - std::ostream &write(float progress) { - auto pos = static_cast(progress * bar_width / 100.0); - for (size_t i = 0, current_display_width = 0; i < bar_width;) { - std::string next; - - if (i < pos) { - next = fill; - current_display_width = unicode::display_width(fill); - } else if (i == pos) { - next = lead; - current_display_width = unicode::display_width(lead); - } else { - next = remainder; - current_display_width = unicode::display_width(remainder); - } - - i += current_display_width; - - if (i > bar_width) { - // `next` is larger than the allowed bar width - // fill with empty space instead - os << std::string((bar_width - (i - current_display_width)), ' '); - break; - } - - os << next; - } - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; - std::string fill; - std::string lead; - std::string remainder; -}; - -class IndeterminateProgressScaleWriter { -public: - IndeterminateProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill, - const std::string &lead) - : os(os), bar_width(bar_width), fill(fill), lead(lead) {} - - std::ostream &write(size_t progress) { - for (size_t i = 0; i < bar_width;) { - std::string next; - size_t current_display_width = 0; - - if (i < progress) { - next = fill; - current_display_width = unicode::display_width(fill); - } else if (i == progress) { - next = lead; - current_display_width = unicode::display_width(lead); - } else { - next = fill; - current_display_width = unicode::display_width(fill); - } - - i += current_display_width; - - if (i > bar_width) { - // `next` is larger than the allowed bar width - // fill with empty space instead - os << std::string((bar_width - (i - current_display_width)), ' '); - break; - } - - os << next; - } - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; - std::string fill; - std::string lead; -}; - -} // namespace details -} // namespace indicators - -#endif - - -#ifndef INDICATORS_PROGRESS_BAR -#define INDICATORS_PROGRESS_BAR - -// #include -#ifndef INDICATORS_STREAM_HELPER -#define INDICATORS_STREAM_HELPER - -// #include -// #include -// #include - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace indicators { -namespace details { - -inline void set_stream_color(std::ostream &os, Color color) { - switch (color) { - case Color::grey: - os << termcolor::grey; - break; - case Color::red: - os << termcolor::red; - break; - case Color::green: - os << termcolor::green; - break; - case Color::yellow: - os << termcolor::yellow; - break; - case Color::blue: - os << termcolor::blue; - break; - case Color::magenta: - os << termcolor::magenta; - break; - case Color::cyan: - os << termcolor::cyan; - break; - case Color::white: - os << termcolor::white; - break; - default: - assert(false); - } -} - -inline void set_font_style(std::ostream &os, FontStyle style) { - switch (style) { - case FontStyle::bold: - os << termcolor::bold; - break; - case FontStyle::dark: - os << termcolor::dark; - break; - case FontStyle::italic: - os << termcolor::italic; - break; - case FontStyle::underline: - os << termcolor::underline; - break; - case FontStyle::blink: - os << termcolor::blink; - break; - case FontStyle::reverse: - os << termcolor::reverse; - break; - case FontStyle::concealed: - os << termcolor::concealed; - break; - case FontStyle::crossed: - os << termcolor::crossed; - break; - default: - break; - } -} - -inline std::ostream &write_duration(std::ostream &os, std::chrono::nanoseconds ns) { - using namespace std; - using namespace std::chrono; - using days = duration>; - char fill = os.fill(); - os.fill('0'); - auto d = duration_cast(ns); - ns -= d; - auto h = duration_cast(ns); - ns -= h; - auto m = duration_cast(ns); - ns -= m; - auto s = duration_cast(ns); - if (d.count() > 0) - os << setw(2) << d.count() << "d:"; - if (h.count() > 0) - os << setw(2) << h.count() << "h:"; - os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's'; - os.fill(fill); - return os; -} - -class BlockProgressScaleWriter { -public: - BlockProgressScaleWriter(std::ostream &os, size_t bar_width) : os(os), bar_width(bar_width) {} - - std::ostream &write(float progress) { - std::string fill_text{"█"}; - std::vector lead_characters{" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}; - auto value = (std::min)(1.0f, (std::max)(0.0f, progress / 100.0f)); - auto whole_width = std::floor(value * bar_width); - auto remainder_width = fmod((value * bar_width), 1.0f); - auto part_width = std::floor(remainder_width * lead_characters.size()); - std::string lead_text = lead_characters[size_t(part_width)]; - if ((bar_width - whole_width - 1) < 0) - lead_text = ""; - for (size_t i = 0; i < whole_width; ++i) - os << fill_text; - os << lead_text; - for (size_t i = 0; i < (bar_width - whole_width - 1); ++i) - os << " "; - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; -}; - -class ProgressScaleWriter { -public: - ProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill, - const std::string &lead, const std::string &remainder) - : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {} - - std::ostream &write(float progress) { - auto pos = static_cast(progress * bar_width / 100.0); - for (size_t i = 0, current_display_width = 0; i < bar_width;) { - std::string next; - - if (i < pos) { - next = fill; - current_display_width = unicode::display_width(fill); - } else if (i == pos) { - next = lead; - current_display_width = unicode::display_width(lead); - } else { - next = remainder; - current_display_width = unicode::display_width(remainder); - } - - i += current_display_width; - - if (i > bar_width) { - // `next` is larger than the allowed bar width - // fill with empty space instead - os << std::string((bar_width - (i - current_display_width)), ' '); - break; - } - - os << next; - } - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; - std::string fill; - std::string lead; - std::string remainder; -}; - -class IndeterminateProgressScaleWriter { -public: - IndeterminateProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill, - const std::string &lead) - : os(os), bar_width(bar_width), fill(fill), lead(lead) {} - - std::ostream &write(size_t progress) { - for (size_t i = 0; i < bar_width;) { - std::string next; - size_t current_display_width = 0; - - if (i < progress) { - next = fill; - current_display_width = unicode::display_width(fill); - } else if (i == progress) { - next = lead; - current_display_width = unicode::display_width(lead); - } else { - next = fill; - current_display_width = unicode::display_width(fill); - } - - i += current_display_width; - - if (i > bar_width) { - // `next` is larger than the allowed bar width - // fill with empty space instead - os << std::string((bar_width - (i - current_display_width)), ' '); - break; - } - - os << next; - } - return os; - } - -private: - std::ostream &os; - size_t bar_width = 0; - std::string fill; - std::string lead; -}; - -} // namespace details -} // namespace indicators - -#endif - -#include -#include -#include -#include -// #include -// #include -// #include -#ifndef INDICATORS_TERMINAL_SIZE -#define INDICATORS_TERMINAL_SIZE -#include - - -#if defined(_WIN32) -#include - -namespace indicators { - -static inline std::pair terminal_size() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - int cols, rows; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); - cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; - rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - return {static_cast(rows), static_cast(cols)}; -} - -static inline size_t terminal_width() { return terminal_size().second; } - -} // namespace indicators - -#else - -#include //ioctl() and TIOCGWINSZ -#include // for STDOUT_FILENO - -namespace indicators { - -static inline std::pair terminal_size() { - struct winsize size{}; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &size); - return {static_cast(size.ws_row), static_cast(size.ws_col)}; -} - -static inline size_t terminal_width() { return terminal_size().second; } - -} // namespace indicators - -#endif - -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace indicators { - -class ProgressBar { - using Settings = - std::tuple; - -public: - template ::type...>::value, - void *>::type = nullptr> - explicit ProgressBar(Args &&... args) - : settings_( - details::get( - option::BarWidth{100}, std::forward(args)...), - details::get( - option::PrefixText{}, std::forward(args)...), - details::get( - option::PostfixText{}, std::forward(args)...), - details::get( - option::Start{"["}, std::forward(args)...), - details::get( - option::End{"]"}, std::forward(args)...), - details::get( - option::Fill{"="}, std::forward(args)...), - details::get( - option::Lead{">"}, std::forward(args)...), - details::get( - option::Remainder{" "}, std::forward(args)...), - details::get( - option::MaxPostfixTextLen{0}, std::forward(args)...), - details::get( - option::Completed{false}, std::forward(args)...), - details::get( - option::ShowPercentage{false}, std::forward(args)...), - details::get( - option::ShowElapsedTime{false}, std::forward(args)...), - details::get( - option::ShowRemainingTime{false}, std::forward(args)...), - details::get( - option::SavedStartTime{false}, std::forward(args)...), - details::get( - option::ForegroundColor{Color::unspecified}, - std::forward(args)...), - details::get( - option::FontStyles{std::vector{}}, - std::forward(args)...), - details::get( - option::MinProgress{0}, std::forward(args)...), - details::get( - option::MaxProgress{100}, std::forward(args)...), - details::get( - option::ProgressType{ProgressType::incremental}, - std::forward(args)...), - details::get( - option::Stream{std::cout}, std::forward(args)...)) { - - // if progress is incremental, start from min_progress - // else start from max_progress - const auto type = get_value(); - if (type == ProgressType::incremental) - progress_ = get_value(); - else - progress_ = get_value(); - } - - template - void set_option(details::Setting &&setting) { - static_assert( - !std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - } - - template - void set_option(const details::Setting &setting) { - static_assert( - !std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = setting.value; - } - - void - set_option(const details::Setting< - std::string, details::ProgressBarOption::postfix_text> &setting) { - std::lock_guard lock(mutex_); - get_value() = setting.value; - if (setting.value.length() > - get_value()) { - get_value() = - setting.value.length(); - } - } - - void set_option( - details::Setting - &&setting) { - std::lock_guard lock(mutex_); - get_value() = - std::move(setting).value; - auto &new_value = get_value(); - if (new_value.length() > - get_value()) { - get_value() = - new_value.length(); - } - } - - void set_progress(size_t new_progress) { - { - std::lock_guard lock(mutex_); - progress_ = new_progress; - } - - save_start_time(); - print_progress(); - } - - void tick() { - { - std::lock_guard lock{mutex_}; - const auto type = get_value(); - if (type == ProgressType::incremental) - progress_ += 1; - else - progress_ -= 1; - } - save_start_time(); - print_progress(); - } - - size_t current() { - std::lock_guard lock{mutex_}; - return (std::min)( - progress_, - size_t(get_value())); - } - - bool is_completed() const { - return get_value(); - } - - void mark_as_completed() { - get_value() = true; - print_progress(); - } - -private: - template - auto get_value() - -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - template - auto get_value() const -> decltype( - (details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - size_t progress_{0}; - Settings settings_; - std::chrono::nanoseconds elapsed_; - std::chrono::time_point start_time_point_; - std::mutex mutex_; - - template friend class MultiProgress; - template friend class DynamicProgress; - std::atomic multi_progress_mode_{false}; - - void save_start_time() { - auto &show_elapsed_time = - get_value(); - auto &saved_start_time = - get_value(); - auto &show_remaining_time = - get_value(); - if ((show_elapsed_time || show_remaining_time) && !saved_start_time) { - start_time_point_ = std::chrono::high_resolution_clock::now(); - saved_start_time = true; - } - } - - std::pair get_prefix_text() { - std::stringstream os; - os << get_value(); - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - - std::pair get_postfix_text() { - std::stringstream os; - const auto max_progress = - get_value(); - - if (get_value()) { - os << " " - << (std::min)(static_cast(static_cast(progress_) / - max_progress * 100), - size_t(100)) - << "%"; - } - - auto &saved_start_time = - get_value(); - - if (get_value()) { - os << " ["; - if (saved_start_time) - details::write_duration(os, elapsed_); - else - os << "00:00s"; - } - - if (get_value()) { - if (get_value()) - os << "<"; - else - os << " ["; - - if (saved_start_time) { - auto eta = std::chrono::nanoseconds( - progress_ > 0 - ? static_cast(std::ceil(float(elapsed_.count()) * - max_progress / progress_)) - : 0); - auto remaining = eta > elapsed_ ? (eta - elapsed_) : (elapsed_ - eta); - details::write_duration(os, remaining); - } else { - os << "00:00s"; - } - - os << "]"; - } else { - if (get_value()) - os << "]"; - } - - os << " " << get_value(); - - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - -public: - void print_progress(bool from_multi_progress = false) { - std::lock_guard lock{mutex_}; - - auto &os = get_value(); - - const auto type = get_value(); - const auto min_progress = - get_value(); - const auto max_progress = - get_value(); - if (multi_progress_mode_ && !from_multi_progress) { - if ((type == ProgressType::incremental && progress_ >= max_progress) || - (type == ProgressType::decremental && progress_ <= min_progress)) { - get_value() = true; - } - return; - } - auto now = std::chrono::high_resolution_clock::now(); - if (!get_value()) - elapsed_ = std::chrono::duration_cast( - now - start_time_point_); - - if (get_value() != - Color::unspecified) - details::set_stream_color( - os, get_value()); - - for (auto &style : get_value()) - details::set_font_style(os, style); - - const auto prefix_pair = get_prefix_text(); - const auto prefix_text = prefix_pair.first; - const auto prefix_length = prefix_pair.second; - os << "\r" << prefix_text; - - os << get_value(); - - details::ProgressScaleWriter writer{ - os, get_value(), - get_value(), - get_value(), - get_value()}; - writer.write(double(progress_) / double(max_progress) * 100.0f); - - os << get_value(); - - const auto postfix_pair = get_postfix_text(); - const auto postfix_text = postfix_pair.first; - const auto postfix_length = postfix_pair.second; - os << postfix_text; - - // Get length of prefix text and postfix text - const auto start_length = get_value().size(); - const auto bar_width = get_value(); - const auto end_length = get_value().size(); - const auto terminal_width = terminal_size().second; - // prefix + bar_width + postfix should be <= terminal_width - const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length); - if (remaining > 0) { - os << std::string(remaining, ' ') << "\r"; - } else if (remaining < 0) { - // Do nothing. Maybe in the future truncate postfix with ... - } - os.flush(); - - if ((type == ProgressType::incremental && progress_ >= max_progress) || - (type == ProgressType::decremental && progress_ <= min_progress)) { - get_value() = true; - } - if (get_value() && - !from_multi_progress) // Don't std::endl if calling from MultiProgress - os << termcolor::reset << std::endl; - } -}; - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_BLOCK_PROGRESS_BAR -#define INDICATORS_BLOCK_PROGRESS_BAR - -// #include -// #include - -#include -#include -#include -// #include -// #include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace indicators { - -class BlockProgressBar { - using Settings = std::tuple; - -public: - template ::type...>::value, - void *>::type = nullptr> - explicit BlockProgressBar(Args &&... args) - : settings_(details::get( - option::ForegroundColor{Color::unspecified}, std::forward(args)...), - details::get(option::BarWidth{100}, - std::forward(args)...), - details::get(option::Start{"["}, - std::forward(args)...), - details::get(option::End{"]"}, - std::forward(args)...), - details::get( - option::PrefixText{""}, std::forward(args)...), - details::get( - option::PostfixText{""}, std::forward(args)...), - details::get( - option::ShowPercentage{true}, std::forward(args)...), - details::get( - option::ShowElapsedTime{false}, std::forward(args)...), - details::get( - option::ShowRemainingTime{false}, std::forward(args)...), - details::get(option::Completed{false}, - std::forward(args)...), - details::get( - option::SavedStartTime{false}, std::forward(args)...), - details::get( - option::MaxPostfixTextLen{0}, std::forward(args)...), - details::get( - option::FontStyles{std::vector{}}, std::forward(args)...), - details::get( - option::MaxProgress{100}, std::forward(args)...), - details::get(option::Stream{std::cout}, - std::forward(args)...)) {} - - template - void set_option(details::Setting &&setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - } - - template - void set_option(const details::Setting &setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = setting.value; - } - - void set_option( - const details::Setting &setting) { - std::lock_guard lock(mutex_); - get_value() = setting.value; - if (setting.value.length() > get_value()) { - get_value() = setting.value.length(); - } - } - - void - set_option(details::Setting &&setting) { - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - auto &new_value = get_value(); - if (new_value.length() > get_value()) { - get_value() = new_value.length(); - } - } - - void set_progress(float value) { - { - std::lock_guard lock{mutex_}; - progress_ = value; - } - save_start_time(); - print_progress(); - } - - void tick() { - { - std::lock_guard lock{mutex_}; - progress_ += 1; - } - save_start_time(); - print_progress(); - } - - size_t current() { - std::lock_guard lock{mutex_}; - return (std::min)(static_cast(progress_), - size_t(get_value())); - } - - bool is_completed() const { return get_value(); } - - void mark_as_completed() { - get_value() = true; - print_progress(); - } - -private: - template - auto get_value() -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - template - auto get_value() const - -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - Settings settings_; - float progress_{0.0}; - std::chrono::time_point start_time_point_; - std::mutex mutex_; - - template friend class MultiProgress; - template friend class DynamicProgress; - std::atomic multi_progress_mode_{false}; - - void save_start_time() { - auto &show_elapsed_time = get_value(); - auto &saved_start_time = get_value(); - auto &show_remaining_time = get_value(); - if ((show_elapsed_time || show_remaining_time) && !saved_start_time) { - start_time_point_ = std::chrono::high_resolution_clock::now(); - saved_start_time = true; - } - } - - std::pair get_prefix_text() { - std::stringstream os; - os << get_value(); - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - - std::pair get_postfix_text() { - std::stringstream os; - const auto max_progress = get_value(); - auto now = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(now - start_time_point_); - - if (get_value()) { - os << " " << (std::min)(static_cast(progress_ / max_progress * 100.0), size_t(100)) - << "%"; - } - - auto &saved_start_time = get_value(); - - if (get_value()) { - os << " ["; - if (saved_start_time) - details::write_duration(os, elapsed); - else - os << "00:00s"; - } - - if (get_value()) { - if (get_value()) - os << "<"; - else - os << " ["; - - if (saved_start_time) { - auto eta = std::chrono::nanoseconds( - progress_ > 0 - ? static_cast(std::ceil(float(elapsed.count()) * - max_progress / progress_)) - : 0); - auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); - details::write_duration(os, remaining); - } else { - os << "00:00s"; - } - - os << "]"; - } else { - if (get_value()) - os << "]"; - } - - os << " " << get_value(); - - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - -public: - void print_progress(bool from_multi_progress = false) { - std::lock_guard lock{mutex_}; - - auto &os = get_value(); - - const auto max_progress = get_value(); - if (multi_progress_mode_ && !from_multi_progress) { - if (progress_ > max_progress) { - get_value() = true; - } - return; - } - - if (get_value() != Color::unspecified) - details::set_stream_color(os, get_value()); - - for (auto &style : get_value()) - details::set_font_style(os, style); - - const auto prefix_pair = get_prefix_text(); - const auto prefix_text = prefix_pair.first; - const auto prefix_length = prefix_pair.second; - os << "\r" << prefix_text; - - os << get_value(); - - details::BlockProgressScaleWriter writer{os, - get_value()}; - writer.write(progress_ / max_progress * 100); - - os << get_value(); - - const auto postfix_pair = get_postfix_text(); - const auto postfix_text = postfix_pair.first; - const auto postfix_length = postfix_pair.second; - os << postfix_text; - - // Get length of prefix text and postfix text - const auto start_length = get_value().size(); - const auto bar_width = get_value(); - const auto end_length = get_value().size(); - const auto terminal_width = terminal_size().second; - // prefix + bar_width + postfix should be <= terminal_width - const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length); - if (remaining > 0) { - os << std::string(remaining, ' ') << "\r"; - } else if (remaining < 0) { - // Do nothing. Maybe in the future truncate postfix with ... - } - os.flush(); - - if (progress_ > max_progress) { - get_value() = true; - } - if (get_value() && - !from_multi_progress) // Don't std::endl if calling from MultiProgress - os << termcolor::reset << std::endl; - } -}; - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_INDETERMINATE_PROGRESS_BAR -#define INDICATORS_INDETERMINATE_PROGRESS_BAR - -// #include - -#include -#include -#include -#include -// #include -// #include -// #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace indicators { - -class IndeterminateProgressBar { - using Settings = - std::tuple; - - enum class Direction { forward, backward }; - - Direction direction_{Direction::forward}; - -public: - template ::type...>::value, - void *>::type = nullptr> - explicit IndeterminateProgressBar(Args &&... args) - : settings_(details::get(option::BarWidth{100}, - std::forward(args)...), - details::get( - option::PrefixText{}, std::forward(args)...), - details::get( - option::PostfixText{}, std::forward(args)...), - details::get(option::Start{"["}, - std::forward(args)...), - details::get(option::End{"]"}, - std::forward(args)...), - details::get(option::Fill{"."}, - std::forward(args)...), - details::get(option::Lead{"<==>"}, - std::forward(args)...), - details::get( - option::MaxPostfixTextLen{0}, std::forward(args)...), - details::get(option::Completed{false}, - std::forward(args)...), - details::get( - option::ForegroundColor{Color::unspecified}, std::forward(args)...), - details::get( - option::FontStyles{std::vector{}}, std::forward(args)...), - details::get(option::Stream{std::cout}, - std::forward(args)...)) { - // starts with [<==>...........] - // progress_ = 0 - - // ends with [...........<==>] - // ^^^^^^^^^^^^^^^^^ bar_width - // ^^^^^^^^^^^^ (bar_width - len(lead)) - // progress_ = bar_width - len(lead) - progress_ = 0; - max_progress_ = get_value() - - get_value().size() + - get_value().size() + - get_value().size(); - } - - template - void set_option(details::Setting &&setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - } - - template - void set_option(const details::Setting &setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = setting.value; - } - - void set_option( - const details::Setting &setting) { - std::lock_guard lock(mutex_); - get_value() = setting.value; - if (setting.value.length() > get_value()) { - get_value() = setting.value.length(); - } - } - - void - set_option(details::Setting &&setting) { - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - auto &new_value = get_value(); - if (new_value.length() > get_value()) { - get_value() = new_value.length(); - } - } - - void tick() { - { - std::lock_guard lock{mutex_}; - if (get_value()) - return; - - progress_ += (direction_ == Direction::forward) ? 1 : -1; - if (direction_ == Direction::forward && progress_ == max_progress_) { - // time to go back - direction_ = Direction::backward; - } else if (direction_ == Direction::backward && progress_ == 0) { - direction_ = Direction::forward; - } - } - print_progress(); - } - - bool is_completed() { return get_value(); } - - void mark_as_completed() { - get_value() = true; - print_progress(); - } - -private: - template - auto get_value() -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - template - auto get_value() const - -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - size_t progress_{0}; - size_t max_progress_; - Settings settings_; - std::chrono::nanoseconds elapsed_; - std::mutex mutex_; - - template friend class MultiProgress; - template friend class DynamicProgress; - std::atomic multi_progress_mode_{false}; - - std::pair get_prefix_text() { - std::stringstream os; - os << get_value(); - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - - std::pair get_postfix_text() { - std::stringstream os; - os << " " << get_value(); - - const auto result = os.str(); - const auto result_size = unicode::display_width(result); - return {result, result_size}; - } - -public: - void print_progress(bool from_multi_progress = false) { - std::lock_guard lock{mutex_}; - - auto &os = get_value(); - - if (multi_progress_mode_ && !from_multi_progress) { - return; - } - if (get_value() != Color::unspecified) - details::set_stream_color(os, get_value()); - - for (auto &style : get_value()) - details::set_font_style(os, style); - - const auto prefix_pair = get_prefix_text(); - const auto prefix_text = prefix_pair.first; - const auto prefix_length = prefix_pair.second; - os << "\r" << prefix_text; - - os << get_value(); - - details::IndeterminateProgressScaleWriter writer{ - os, get_value(), - get_value(), - get_value()}; - writer.write(progress_); - - os << get_value(); - - const auto postfix_pair = get_postfix_text(); - const auto postfix_text = postfix_pair.first; - const auto postfix_length = postfix_pair.second; - os << postfix_text; - - // Get length of prefix text and postfix text - const auto start_length = get_value().size(); - const auto bar_width = get_value(); - const auto end_length = get_value().size(); - const auto terminal_width = terminal_size().second; - // prefix + bar_width + postfix should be <= terminal_width - const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length); - if (remaining > 0) { - os << std::string(remaining, ' ') << "\r"; - } else if (remaining < 0) { - // Do nothing. Maybe in the future truncate postfix with ... - } - os.flush(); - - if (get_value() && - !from_multi_progress) // Don't std::endl if calling from MultiProgress - os << termcolor::reset << std::endl; - } -}; - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_MULTI_PROGRESS -#define INDICATORS_MULTI_PROGRESS -#include -#include -#include -#include -#include - -// #include -// #include -#ifndef INDICATORS_CURSOR_MOVEMENT -#define INDICATORS_CURSOR_MOVEMENT - -#if defined(_MSC_VER) -#if !defined(NOMINMAX) -#define NOMINMAX -#endif -#include -#include -#else -#include -#endif - -namespace indicators { - -#ifdef _MSC_VER - -static inline void move(int x, int y) { - auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - if (!hStdout) - return; - - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(hStdout, &csbiInfo); - - COORD cursor; - - cursor.X = csbiInfo.dwCursorPosition.X + x; - cursor.Y = csbiInfo.dwCursorPosition.Y + y; - SetConsoleCursorPosition(hStdout, cursor); -} - -static inline void move_up(int lines) { move(0, -lines); } -static inline void move_down(int lines) { move(0, -lines); } -static inline void move_right(int cols) { move(cols, 0); } -static inline void move_left(int cols) { move(-cols, 0); } - -#else - -static inline void move_up(int lines) { std::cout << "\033[" << lines << "A"; } -static inline void move_down(int lines) { std::cout << "\033[" << lines << "B"; } -static inline void move_right(int cols) { std::cout << "\033[" << cols << "C"; } -static inline void move_left(int cols) { std::cout << "\033[" << cols << "D"; } - -#endif - -} // namespace indicators - -#endif -// #include - -namespace indicators { - -template class MultiProgress { -public: - template ::type> - explicit MultiProgress(Indicators &... bars) { - bars_ = {bars...}; - for (auto &bar : bars_) { - bar.get().multi_progress_mode_ = true; - } - } - - template - typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(size_t value) { - if (!bars_[index].get().is_completed()) - bars_[index].get().set_progress(value); - print_progress(); - } - - template - typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(float value) { - if (!bars_[index].get().is_completed()) - bars_[index].get().set_progress(value); - print_progress(); - } - - template - typename std::enable_if<(index >= 0 && index < count), void>::type tick() { - if (!bars_[index].get().is_completed()) - bars_[index].get().tick(); - print_progress(); - } - - template - typename std::enable_if<(index >= 0 && index < count), bool>::type is_completed() const { - return bars_[index].get().is_completed(); - } - -private: - std::atomic started_{false}; - std::mutex mutex_; - std::vector> bars_; - - bool _all_completed() { - bool result{true}; - for (size_t i = 0; i < count; ++i) - result &= bars_[i].get().is_completed(); - return result; - } - -public: - void print_progress() { - std::lock_guard lock{mutex_}; - if (started_) - move_up(count); - for (auto &bar : bars_) { - bar.get().print_progress(true); - std::cout << "\n"; - } - std::cout << termcolor::reset; - if (!started_) - started_ = true; - } -}; - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_DYNAMIC_PROGRESS -#define INDICATORS_DYNAMIC_PROGRESS - -#include -#include -// #include -// #include -// #include -#include -#include -#include - -namespace indicators { - -template class DynamicProgress { - using Settings = std::tuple; - -public: - template explicit DynamicProgress(Indicators &... bars) { - bars_ = {bars...}; - for (auto &bar : bars_) { - bar.get().multi_progress_mode_ = true; - ++total_count_; - ++incomplete_count_; - } - } - - Indicator &operator[](size_t index) { - print_progress(); - std::lock_guard lock{mutex_}; - return bars_[index].get(); - } - - size_t push_back(Indicator &bar) { - std::lock_guard lock{mutex_}; - bar.multi_progress_mode_ = true; - bars_.push_back(bar); - return bars_.size() - 1; - } - - template - void set_option(details::Setting &&setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - } - - template - void set_option(const details::Setting &setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = setting.value; - } - -private: - Settings settings_; - std::atomic started_{false}; - std::mutex mutex_; - std::vector> bars_; - std::atomic total_count_{0}; - std::atomic incomplete_count_{0}; - - template - auto get_value() -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - template - auto get_value() const - -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - -public: - void print_progress() { - std::lock_guard lock{mutex_}; - auto &hide_bar_when_complete = get_value(); - if (hide_bar_when_complete) { - // Hide completed bars - if (started_) { - for (size_t i = 0; i < incomplete_count_; ++i) - std::cout << "\033[A\r\033[K" << std::flush; - } - incomplete_count_ = 0; - for (auto &bar : bars_) { - if (!bar.get().is_completed()) { - bar.get().print_progress(true); - std::cout << "\n"; - ++incomplete_count_; - } - } - if (!started_) - started_ = true; - } else { - // Don't hide any bars - if (started_) { - for (size_t i = 0; i < total_count_; ++i) - std::cout << "\x1b[A"; - } - for (auto &bar : bars_) { - bar.get().print_progress(true); - std::cout << "\n"; - } - if (!started_) - started_ = true; - } - total_count_ = bars_.size(); - std::cout << termcolor::reset; - } -}; - -} // namespace indicators - -#endif - - -#ifndef INDICATORS_PROGRESS_SPINNER -#define INDICATORS_PROGRESS_SPINNER - -// #include - -#include -#include -#include -#include -// #include -// #include -#include -#include -#include -#include -#include -#include -#include - -namespace indicators { - -class ProgressSpinner { - using Settings = - std::tuple; - -public: - template ::type...>::value, - void *>::type = nullptr> - explicit ProgressSpinner(Args &&... args) - : settings_( - details::get( - option::ForegroundColor{Color::unspecified}, std::forward(args)...), - details::get(option::PrefixText{}, - std::forward(args)...), - details::get(option::PostfixText{}, - std::forward(args)...), - details::get(option::ShowPercentage{true}, - std::forward(args)...), - details::get( - option::ShowElapsedTime{false}, std::forward(args)...), - details::get( - option::ShowRemainingTime{false}, std::forward(args)...), - details::get(option::ShowSpinner{true}, - std::forward(args)...), - details::get( - option::SavedStartTime{false}, std::forward(args)...), - details::get(option::Completed{false}, - std::forward(args)...), - details::get( - option::MaxPostfixTextLen{0}, std::forward(args)...), - details::get( - option::SpinnerStates{ - std::vector{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}}, - std::forward(args)...), - details::get( - option::FontStyles{std::vector{}}, std::forward(args)...), - details::get(option::MaxProgress{100}, - std::forward(args)...), - details::get(option::Stream{std::cout}, - std::forward(args)...)) {} - - template - void set_option(details::Setting &&setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - } - - template - void set_option(const details::Setting &setting) { - static_assert(!std::is_same( - std::declval()))>::type>::value, - "Setting has wrong type!"); - std::lock_guard lock(mutex_); - get_value() = setting.value; - } - - void set_option( - const details::Setting &setting) { - std::lock_guard lock(mutex_); - get_value() = setting.value; - if (setting.value.length() > get_value()) { - get_value() = setting.value.length(); - } - } - - void - set_option(details::Setting &&setting) { - std::lock_guard lock(mutex_); - get_value() = std::move(setting).value; - auto &new_value = get_value(); - if (new_value.length() > get_value()) { - get_value() = new_value.length(); - } - } - - void set_progress(size_t value) { - { - std::lock_guard lock{mutex_}; - progress_ = value; - } - save_start_time(); - print_progress(); - } - - void tick() { - { - std::lock_guard lock{mutex_}; - progress_ += 1; - } - save_start_time(); - print_progress(); - } - - size_t current() { - std::lock_guard lock{mutex_}; - return (std::min)(progress_, size_t(get_value())); - } - - bool is_completed() const { return get_value(); } - - void mark_as_completed() { - get_value() = true; - print_progress(); - } - -private: - Settings settings_; - size_t progress_{0}; - size_t index_{0}; - std::chrono::time_point start_time_point_; - std::mutex mutex_; - - template - auto get_value() -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - template - auto get_value() const - -> decltype((details::get_value(std::declval()).value)) { - return details::get_value(settings_).value; - } - - void save_start_time() { - auto &show_elapsed_time = get_value(); - auto &show_remaining_time = get_value(); - auto &saved_start_time = get_value(); - if ((show_elapsed_time || show_remaining_time) && !saved_start_time) { - start_time_point_ = std::chrono::high_resolution_clock::now(); - saved_start_time = true; - } - } - -public: - void print_progress() { - std::lock_guard lock{mutex_}; - - auto &os = get_value(); - - const auto max_progress = get_value(); - auto now = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(now - start_time_point_); - - if (get_value() != Color::unspecified) - details::set_stream_color(os, get_value()); - - for (auto &style : get_value()) - details::set_font_style(os, style); - - os << get_value(); - if (get_value()) - os << get_value() - [index_ % get_value().size()]; - if (get_value()) { - os << " " << std::size_t(progress_ / double(max_progress) * 100) << "%"; - } - - if (get_value()) { - os << " ["; - details::write_duration(os, elapsed); - } - - if (get_value()) { - if (get_value()) - os << "<"; - else - os << " ["; - auto eta = std::chrono::nanoseconds( - progress_ > 0 - ? static_cast(std::ceil(float(elapsed.count()) * - max_progress / progress_)) - : 0); - auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); - details::write_duration(os, remaining); - os << "]"; - } else { - if (get_value()) - os << "]"; - } - - if (get_value() == 0) - get_value() = 10; - os << " " << get_value() - << std::string(get_value(), ' ') << "\r"; - os.flush(); - index_ += 1; - if (progress_ > max_progress) { - get_value() = true; - } - if (get_value()) - os << termcolor::reset << std::endl; - } -}; - -} // namespace indicators - -#endif - diff --git a/main.cpp b/main.cpp index 7b3291a..3eae6ce 100644 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,7 @@ #include #include #include -#include -#include -#define RMT_ENABLED 0 // Lib includes #pragma GCC diagnostic push @@ -14,8 +11,6 @@ #include #pragma GCC diagnostic pop -#include - // Internal includes #include "rtweekend.hpp" #include "color.hpp" @@ -23,59 +18,23 @@ #include "sphere.hpp" #include "camera.hpp" -#ifdef DEBUG -#define print_timers() print_timers_() -#else -#define print_timers() -#endif - -// Threading structs -struct thread_args -{ - int32_t thread_id; - int32_t start; - int32_t end; -}; - -// Function signatures color ray_color(const ray& r, const hittable& world, int32_t depth); -float hit_sphere(const point3& center, float radius, const ray& r); -void *raytrace_lines(void *arg); -hittable_list random_scene(); +double hit_sphere(const point3& center, double radius, const ray& r); +hittable_list random_scene(); -// Global vars -indicators::DynamicProgress progress_bars; -const char *default_file = "image.ppm"; -FILE *output_file_handle; - -// Image -float aspect_ratio; -int32_t image_width; -int32_t image_height; -int32_t samples_per_pixel; -int32_t max_depth; - -color *image; -uint64_t bytes_per_line; -uint64_t bytes_per_pixel; - -// World -hittable_list world; -camera *global_camera; - -hittable_list random_scene() { - hittable_list world; +hittable_list random_scene() { + hittable_list world; auto ground_material = make_shared(color(0.5, 0.5, 0.5)); - world.add(sphere(point3(0,-1000,0), 1000, ground_material)); + world.add(make_shared(point3(0,-1000,0), 1000, ground_material)); for (int32_t a = -11; a < 11; a++) { for (int32_t b = -11; b < 11; b++) { - float choose_mat = random_float(); - point3 center(a + 0.9*random_float(), 0.2, b + 0.9*random_float()); + double choose_mat = random_double(); + point3 center(a + 0.9*random_double(), 0.2, b + 0.9*random_double()); if ((center - point3(4, 0.2, 0)).length() > 0.9) { @@ -85,40 +44,39 @@ hittable_list random_scene() { // diffuse color albedo = color::random() * color::random(); sphere_material = make_shared(albedo); - world.add(sphere(center, 0.2, sphere_material)); + world.add(make_shared(center, 0.2, sphere_material)); } else if (choose_mat < 0.95) { // metal color albedo = color::random(0.5, 1); - float fuzz = random_float(0, 0.5); + double fuzz = random_double(0, 0.5); sphere_material = make_shared(albedo, fuzz); - world.add(sphere(center, 0.2, sphere_material)); + world.add(make_shared(center, 0.2, sphere_material)); } else { // glass sphere_material = make_shared(1.5); - world.add(sphere(center, 0.2, sphere_material)); + world.add(make_shared(center, 0.2, sphere_material)); } } } } auto material1 = make_shared(1.5); - world.add(sphere(point3(0, 1, 0), 1.0, material1)); + world.add(make_shared(point3(0, 1, 0), 1.0, material1)); auto material2 = make_shared(color(0.4, 0.2, 0.1)); - world.add(sphere(point3(-4, 1, 0), 1.0, material2)); + world.add(make_shared(point3(-4, 1, 0), 1.0, material2)); auto material3 = make_shared(color(0.7, 0.6, 0.5), 0.0); - world.add(sphere(point3(4, 1, 0), 1.0, material3)); + world.add(make_shared(point3(4, 1, 0), 1.0, material3)); return world; } -template -color ray_color(const ray& r, hittable_list& world, int32_t depth, int32_t thread_id) +color ray_color(const ray& r, const hittable& world, int32_t depth) { rmt_ScopedCPUSample(Scatter, RMTSF_Aggregate | RMTSF_Recursive); if (depth <= 0) @@ -132,11 +90,11 @@ color ray_color(const ray& r, hittable_list& world, int32_t depth, int32_t th ray scattered; color attenuation; rmt_BeginCPUSample(Scatter, RMTSF_Aggregate); - bool visible = rec.mat_ptr->scatter(r, rec, attenuation, scattered, thread_id); + bool visible = rec.mat_ptr->scatter(r, rec, attenuation, scattered); rmt_EndCPUSample(); if (visible) { - return attenuation * ray_color(scattered, world, depth-1, thread_id); + return attenuation * ray_color(scattered, world, depth-1); } else { @@ -144,305 +102,85 @@ color ray_color(const ray& r, hittable_list& world, int32_t depth, int32_t th } } vec3 unit_direction = normalize(r.direction); - float t = 0.5 * (unit_direction.y + 1.0); + double t = 0.5 * (unit_direction.y + 1.0); return (1-t) * color(1,1,1) + t*color(0.5,0.7,1.0); } -float hit_sphere(const point3& center, float radius, const ray& r) +double hit_sphere(const point3& center, double radius, const ray& r) { vec3 oc = r.origin - center; - float a = r.direction.length_squared(); - float half_b = dot(oc, r.direction); - float c = oc.length_squared() - radius*radius; - float discriminant = half_b*half_b - a*c; + double a = r.direction.length_squared(); + double half_b = dot(oc, r.direction); + double c = oc.length_squared() - radius*radius; + double discriminant = half_b*half_b - a*c; if (discriminant < 0) return -1; else return (-half_b - sqrt(discriminant)) / a; } -int32_t main(int argc, char *argv[]) -{ - - - - - /* Argument parsing */ - int32_t c; - bool using_default_output = true; - - while (1) - { - static struct option long_options[] = - { - {"output", required_argument, 0, 'o'}, - {0, 0, 0, 0} - }; - /* getopt_long stores the option index here. */ - int option_index = 0; - - c = getopt_long (argc, argv, "o:", - long_options, &option_index); - - /* Detect the end of the options. */ - if (c == -1) - break; - - switch (c) - { - case 0: - /* If this option set a flag, do nothing else now. */ - if (long_options[option_index].flag != 0) - break; - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case 'o': - using_default_output = false; - output_file_handle = fopen(optarg, "w"); - break; - - case '?': - /* getopt_long already printed an error message. */ - break; - - default: - abort(); - } - } - - if (using_default_output) - { - output_file_handle = fopen(default_file, "w"); - } - - +int32_t main() +{ /* Profiling library initialization */ Remotery *rmt; if (RMT_ERROR_NONE != rmt_CreateGlobalInstance(&rmt)) { fprintf(stderr, "Error starting Remotery\n"); } - - //indicators::show_console_cursor(false); - - - // Get the number of logical CPUs - int32_t ncores = sysconf(_SC_NPROCESSORS_ONLN); - // Initialize and seed the random number generators - pcg_table = (pcg32_random_t *) malloc(sizeof(pcg32_random_t) * ncores); - for (int32_t i = 0; i < ncores; ++i) - { - struct timespec ts; - if (timespec_get(&ts, TIME_UTC)) - { - // Use higher quality seed - uint64_t seed = (uint64_t)(ts.tv_nsec ^ ts.tv_sec); - pcg_table[i] = { seed, seed }; - } - else - { - // Error, use default seed - pcg_table[i] = default_pcg; - } - - - - } + // Image - aspect_ratio = 3.0 / 2.0; - image_width = 1200; - image_height = (int32_t) (image_width / aspect_ratio); - samples_per_pixel = 500; - max_depth = 50; - - image = (color*) malloc(image_width * image_height * sizeof(color)); - bytes_per_line = sizeof(color) * image_width; - bytes_per_pixel = sizeof(color); + const double aspect_ratio = 3.0 / 2.0; + const int32_t image_width = 1200; + const int32_t image_height = (int32_t) (image_width / aspect_ratio); + int32_t samples_per_pixel = 500; + const int32_t max_depth = 50; if (getenv("SPP")) { samples_per_pixel = strtol(getenv("SPP"), NULL, 10); } + + // World - world = random_scene(); + hittable_list world = random_scene(); // Camera point3 lookfrom(13,2,3); point3 lookat(0,0,0); vec3 vup(0,1,0); - float dist_to_focus = 10.0; - float aperture = 0.1; + double dist_to_focus = 10.0; + double aperture = 0.1; + + camera cam(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus); - camera cam = camera(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus); - global_camera = &cam; - // Render - fprintf(output_file_handle, "P3\n%d %d\n255\n", image_width, image_height); + printf("P3\n%d %d\n255\n", image_width, image_height); - - std::vector threads; - std::vector args; - threads.reserve(ncores); - args.reserve(ncores); - - std::vector bar_memory; - bar_memory.reserve(ncores); - - for (int32_t i = 0; i < ncores; ++i) + + for (int32_t j = image_height - 1; j >= 0; --j) { - - bar_memory[i] = new indicators::BlockProgressBar{indicators::option::BarWidth{50}, - indicators::option::ForegroundColor{indicators::Color::white}, - indicators::option::ShowElapsedTime{true}, - indicators::option::ShowRemainingTime{true}, - indicators::option::PrefixText{"Thread #" + std::to_string(i)} - }; - - progress_bars.push_back(*bar_memory[i]); - - int32_t start; - int32_t end; - - // Divide work among cores - start = image_height/ncores * i; - end = image_height/ncores * (i+1); - - // Make sure we complete the whole picture even if the work is not perfectly divisible - if (i == ncores) - end = image_height; - - args[i].start = start; - args[i].end = end; - args[i].thread_id = i; - - // TODO: Check for errors - pthread_create(&threads[i], NULL, raytrace_lines, &args[i]); - - } - - for (int32_t i = 0; i < ncores; ++i) - { - switch (pthread_join(threads[i], NULL)) - { - case EDEADLK: - fprintf(stderr, "A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the calling thread.\n"); - break; - - case EINVAL: - fprintf(stderr, "thread is not a joinable thread OR\n" - "Another thread is already waiting to join with this thread.\n"); - break; - - case ESRCH: - fprintf(stderr, "No thread with the ID thread could be found.\n"); - break; - default: - break; - } - } - - write_image(image, image_width*image_height, output_file_handle, samples_per_pixel); - - - - /* Obsolete non-threaded implementation */ - - // for (int32_t j = image_height - 1; j >= 0; --j) - // { - // rmt_ScopedCPUSample(OuterLoop, RMTSF_Aggregate); - // fprintf(stderr, "\rScanlines remaining: %d ", j); - // print_timers(); - // fflush(stderr); - - - - // for (int32_t i = 0; i < image_width; ++i) - // { - // rmt_ScopedCPUSample(InnerLoop, RMTSF_Aggregate); - // color pixel_color = color(0,0,0); + rmt_ScopedCPUSample(OuterLoop, RMTSF_Aggregate); + fprintf(stderr, "\rScanlines remaining: %d ", j); + fflush(stderr); + for (int32_t i = 0; i < image_width; ++i) + { + rmt_ScopedCPUSample(InnerLoop, RMTSF_Aggregate); + color pixel_color = color(0,0,0); - // for (int32_t s = 0; s < samples_per_pixel; ++s) - // { - // float u = ((i + random_float()) / (image_width-1)); - // float v = ((j + random_float()) / (image_height-1)); - // ray r = cam.get_ray(u,v); - // pixel_color += ray_color(r, world, max_depth); - // } + for (int32_t s = 0; s < samples_per_pixel; ++s) + { + double u = ((i + random_double()) / (image_width-1)); + double v = ((j + random_double()) / (image_height-1)); + ray r = cam.get_ray(u,v); + pixel_color += ray_color(r, world, max_depth); + } - // write_color(output_file_handle, pixel_color, samples_per_pixel); - // } - // } + write_color(stdout, pixel_color, samples_per_pixel); + } + } fprintf(stderr, "\nDone\n"); rmt_DestroyGlobalInstance(rmt); - free(image); - fclose(output_file_handle); - //indicators::show_console_cursor(true); } - -void *raytrace_lines(void *arg) -{ - - thread_args arguments = *((thread_args*)arg); - - int32_t start = arguments.start; - int32_t end = arguments.end; - int32_t thread_id = arguments.thread_id; - - for (int32_t j = end - 1; j >= start; --j) - { - - int32_t lines_expected = end-start; - int32_t lines_completed = end-j; - progress_bars[thread_id].set_option(indicators::option::PostfixText{std::to_string(lines_completed) + "/" + std::to_string(lines_expected)}); - - progress_bars[thread_id].set_progress(((float)lines_completed/lines_expected)*100); - rmt_ScopedCPUSample(OuterLoop, RMTSF_Aggregate); - for (int32_t i = 0; i < image_width; ++i) - { - color pixel_color = color(0,0,0); - for (int32_t s = 0; s < samples_per_pixel; ++s) - { - float u = ((i + random_float(thread_id)) / (image_width-1)); - float v = ((j + random_float(thread_id)) / (image_height-1)); - ray r = global_camera->get_ray(u,v, thread_id); - pixel_color += ray_color(r, world, max_depth, thread_id); - } - int32_t index = j * image_width + i; - image[index] = pixel_color; - } - } - return nullptr; -} - -#ifdef DEBUG -debug_record debug_record_array[__COUNTER__]; - -void print_timers_() -{ - for (uint32_t i = 0; - i < sizeof(debug_record_array) / sizeof(debug_record_array[0]); - ++i) - { - debug_record *record = &debug_record_array[i]; - fprintf(stderr, - "%d: %s:%s:%d; " - "Cycles = %ld; " - "Hit count %ld; " - "Cycles/hit %f; " - "Time %f", - i, record->filename, record->function_name, record->line_number, - record->cycles, - record->hit_count, - (double)record->cycles / record->hit_count, - (double)record->cycles / CLOCKS_PER_SEC); - } -} - -#endif diff --git a/material.hpp b/material.hpp index 5665533..5792e38 100644 --- a/material.hpp +++ b/material.hpp @@ -4,7 +4,7 @@ #include "rtweekend.hpp" struct material { - virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, int32_t thread_id = 0) const = 0; + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const = 0; }; struct lambertian : material { @@ -15,9 +15,9 @@ struct lambertian : material { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" - virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, int32_t thread_id = 0) const override + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override { - vec3 scatter_direction = rec.normal + random_unit_vector(thread_id); + vec3 scatter_direction = rec.normal + random_unit_vector(); /* NOTE: it is possible that the random vector we generate is exactly opposite to the normal vector, in which case it will sum to a near-zero scatter vector and generate degenerate results. @@ -37,18 +37,18 @@ struct lambertian : material { struct metal : material { /* Attributes */ color albedo; - float fuzz; + double fuzz; // Constructor - metal(const color& c, float f) + metal(const color& c, double f) { albedo = c; fuzz = f; }; - virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, int32_t thread_id) const override + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override { vec3 reflected = reflect(normalize(r_in.direction), rec.normal); - scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere(thread_id)); + scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere()); attenuation = albedo; return (dot(scattered.direction, rec.normal) > 0); } @@ -57,37 +57,37 @@ struct metal : material { struct dielectric : material { /* Attributes */ - float ri; // refraction index + double ri; // refraction index // Constructor - dielectric(float refraction_index) { ri = refraction_index; } + dielectric(double refraction_index) { ri = refraction_index; } /* Methods */ // Schlick's approximation of reflectance - static float reflectance(float cosine, float ref_idx) + static double reflectance(double cosine, double ref_idx) { - float r0 = (1-ref_idx) / (1+ref_idx); + double r0 = (1-ref_idx) / (1+ref_idx); r0 = r0*r0; return r0 + (1-r0)*pow((1 - cosine), 5); } /* Virtual methods */ - virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, int32_t thread_id) const override + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override { attenuation = color(1,1,1); - float refraction_ratio = rec.front_face ? (1.0/ri) : ri; + double refraction_ratio = rec.front_face ? (1.0/ri) : ri; vec3 unit_direction = normalize(r_in.direction); - float cos_theta = fmin(dot(-unit_direction, rec.normal), 1); - float sin_theta = sqrt(1.0 - cos_theta*cos_theta); + double cos_theta = fmin(dot(-unit_direction, rec.normal), 1); + double sin_theta = sqrt(1.0 - cos_theta*cos_theta); bool cannot_refract = refraction_ratio * sin_theta > 1.0; vec3 direction; - if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_float(thread_id)) + if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double()) direction = reflect(unit_direction, rec.normal); else direction = refract(unit_direction, rec.normal, refraction_ratio); diff --git a/random.h b/random.h deleted file mode 100644 index b5f66e7..0000000 --- a/random.h +++ /dev/null @@ -1,15 +0,0 @@ -// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org -// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) - -typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t; - -uint32_t pcg32_random_r(pcg32_random_t* rng) -{ - uint64_t oldstate = rng->state; - // Advance internal state - rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1); - // Calculate output function (XSH RR), uses old state for max ILP - uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; - uint32_t rot = oldstate >> 59u; - return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); -} diff --git a/ray.hpp b/ray.hpp index 8ad69eb..ac4231e 100644 --- a/ray.hpp +++ b/ray.hpp @@ -24,7 +24,7 @@ struct ray { } // Returns position after time t - point3 at(float t) const + point3 at(double t) const { return origin + t*direction; } diff --git a/rtweekend.hpp b/rtweekend.hpp index 136efe7..8468343 100644 --- a/rtweekend.hpp +++ b/rtweekend.hpp @@ -3,40 +3,36 @@ #include #include -#include -#include -#include "timer.hpp" -#include "random.h" -pcg32_random_t *pcg_table; -pcg32_random_t default_pcg = { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }; +/* Utility macros */ + +#define TIMED_BLOCK_2(c, flags) rmt_ScopedCPUSample(Counter##c, flags) +#define TIMED_BLOCK_1(c, flags) TIMED_BLOCK_2(c, flags) +#define TIMED_BLOCK(flags) TIMED_BLOCK_1(__COUNTER__, flags) + +// #define TIMED_BLOCK_(counter, flags) rmt_ScopedCPUSample(counter, flags) +// #define TIMED_BLOCK(flags) TIMED_BLOCK_(__COUNTER__, flags) /* Utility functions */ -inline float degrees_to_radians(float d) +double degrees_to_radians(double d) { return d * M_PI / 180; } -/* Returns a float in the range [0,1) */ -inline float random_float_() +/* Returns a double in the range [0,1) */ +inline double random_double() { return rand() * (1.0 / RAND_MAX); } -/* Returns a float in the range [0,1) */ -inline float random_float(int32_t thread_id = 0) +/* Returns a double in the range [min,max) */ +inline double random_double(double min, double max) { - return pcg32_random_r(&pcg_table[thread_id]) * (1.0 / UINT32_MAX); -} - -/* Returns a float in the range [min,max) */ -inline float random_float(float min, float max, int32_t thread_id = 0) -{ - return min + (max-min) * random_float(thread_id); + return min + (max-min) * random_double(); } /* Clamps a value between [min,max] */ -inline float clamp(float v, float min, float max) +inline double clamp(double v, double min, double max) { return v < min ? min : v > max ? max : v; } @@ -54,7 +50,7 @@ struct hit_record { point3 p; vec3 normal; std::shared_ptr mat_ptr; - float t; + double t; bool front_face; inline void set_face_normal(const ray& r, const vec3& outward_normal) diff --git a/sphere.hpp b/sphere.hpp index a913a31..c54965a 100644 --- a/sphere.hpp +++ b/sphere.hpp @@ -7,11 +7,11 @@ struct sphere : hittable { /* Attributes */ point3 center; - float radius; + double radius; std::shared_ptr mat_ptr; /* Contructor */ - sphere(point3 c, float r, std::shared_ptr m) + sphere(point3 c, double r, std::shared_ptr m) { center = c; radius = r; @@ -19,42 +19,49 @@ struct sphere : hittable { } /* Virtual methods declaration */ - bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const; + virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const override; }; /* Virtual method implementations */ -bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const +bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const { - /* NOTE: This function is called too many times (and too fast) for it to be - profiled in a usual way using Remotery. */ - - TIMED_BLOCK(); - - vec3 oc = r.origin - center; - float a = r.direction.length_squared(); - float half_b = dot(oc, r.direction); - float c = oc.length_squared() - radius*radius; + rmt_ScopedCPUSample(Sphere_Hit, RMTSF_Aggregate); - float discriminant = half_b*half_b - a*c; + // Part 1 + + vec3 oc = r.origin - center; + double a = r.direction.length_squared(); + double half_b = dot(oc, r.direction); + double c = oc.length_squared() - radius*radius; + + + // Part 2 + + double discriminant = half_b*half_b - a*c; if (discriminant < 0) return false; - float sqrtd = sqrt(discriminant); + double sqrtd = sqrt(discriminant); + // Find the nearest root that lies in the acceptable range - float root = (-half_b - sqrtd) / a; + // Part 3 + + double root = (-half_b - sqrtd) / a; if (root < t_min || t_max < root) { root = (-half_b + sqrtd) / a; if (root < t_min || t_max < root) return false; } - + + // Part 4 + rec.t = root; rec.p = r.at(rec.t); vec3 outward_normal = (rec.p - center) / radius; rec.set_face_normal(r, outward_normal); - rec.mat_ptr = mat_ptr; - + rec.mat_ptr = mat_ptr; + return true; } diff --git a/timer.hpp b/timer.hpp deleted file mode 100644 index 6a2c689..0000000 --- a/timer.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include "rtweekend.hpp" - -#ifdef DEBUG -#define TIMED_BLOCK__(number, ...) timed_block timed_block_##Number(__COUNTER__, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) -#define TIMED_BLOCK_(number, ...) TIMED_BLOCK__(number, ##__VA_ARGS__) -#define TIMED_BLOCK(...) TIMED_BLOCK_(__LINE__, ##__VA_ARGS__) -#else -#define TIMED_BLOCK(...) -#endif - -#ifdef DEBUG -struct debug_record -{ - uint64_t cycles; - uint64_t hit_count; - const char *filename; - const char *function_name; - - uint32_t line_number; - -}; - - -extern debug_record debug_record_array[]; - -struct timed_block { - // TODO: Thread safety - debug_record *record; - - timed_block(int counter, const char *filename, int line_number, const char *function_name, int hit_count = 1) - { - record = debug_record_array + counter; - record->filename = filename; - record->line_number = line_number; - record->function_name = function_name; - record->cycles -= __rdtsc(); - record->hit_count += hit_count; - } - ~timed_block() - { - record->cycles += __rdtsc(); - } -}; -#endif diff --git a/vec3.hpp b/vec3.hpp index 2396617..b7340a1 100644 --- a/vec3.hpp +++ b/vec3.hpp @@ -5,12 +5,12 @@ struct vec3 { /* Members */ - float x; - float y; - float z; + double x; + double y; + double z; // Constructor proper. Values default to 0 - vec3(float x = 0, float y = 0, float z = 0) + vec3(double x = 0, double y = 0, double z = 0) { this->x = x; this->y = y; @@ -35,7 +35,7 @@ struct vec3 { } // Scalar multiplication - vec3& operator*=(const float t) + vec3& operator*=(const double t) { x *= t; y *= t; @@ -44,7 +44,7 @@ struct vec3 { } // Division by a scalar t - vec3& operator/=(const float t) + vec3& operator/=(const double t) { x /= t; y /= t; @@ -54,33 +54,33 @@ struct vec3 { /* Methods */ - float length() const + double length() const { return sqrt(x*x + y*y + z*z); } // Length squared, useful for some calculations - float length_squared() const + double length_squared() const { return x*x + y*y + z*z; } // Get a vec3 with random components in the range [0,1) - inline static vec3 random(int32_t thread_id = 0) + inline static vec3 random() { - return vec3(random_float(thread_id), random_float(thread_id), random_float(thread_id)); + return vec3(random_double(), random_double(), random_double()); } // Get a vec3 with random components in the range [min, max) - inline static vec3 random(float min, float max, int32_t thread_id = 0) + inline static vec3 random(double min, double max) { - return vec3(random_float(min, max, thread_id), random_float(min, max, thread_id), random_float(min, max, thread_id)); + return vec3(random_double(min, max), random_double(min, max), random_double(min, max)); } // Check if all vector components are near zero bool near_zero() const { - float s = 1e-8; + double s = 1e-8; return (fabs(x) < s) && (fabs(y) < s) && (fabs(z) < s); } }; @@ -92,11 +92,6 @@ typedef vec3 color; /* More overloads */ -inline bool operator==(const vec3 &u, const vec3 &v) -{ - return u.x == v.x && u.y == v.y && u.z == v.z; -} - // Straightforward vector sum inline vec3 operator+(const vec3 &u, const vec3 &v) { @@ -122,24 +117,24 @@ inline vec3 operator*(const vec3 &u, const vec3 &v) } // Scalar product -inline vec3 operator*(float t,const vec3 &v) +inline vec3 operator*(double t,const vec3 &v) { return vec3(t*v.x, t*v.y, t*v.z); } -inline vec3 operator*(const vec3 &v, float t) +inline vec3 operator*(const vec3 &v, double t) { return t * v; } // Vector division by scalar. Note that we redefine it as multiplying by 1/t to avoid division by 0 -inline vec3 operator/(vec3 v, float t) +inline vec3 operator/(vec3 v, double t) { return 1/t * v; } // Straightforward dot product -inline float dot(const vec3 &u, const vec3 &v) +inline double dot(const vec3 &u, const vec3 &v) { return u.x*v.x + u.y*v.y + u.z*v.z; @@ -162,12 +157,12 @@ inline vec3 normalize(const vec3 v) } // Returns a vec3 of random components between [-1,1) that is inside a unit sphere -vec3 random_in_unit_sphere(int32_t thread_id) +vec3 random_in_unit_sphere() { // Iterate until we find a vector with length < 1 while (true) { - vec3 p = vec3::random(-1,1, thread_id); + vec3 p = vec3::random(-1,1); if (p.length_squared() >= 1) continue; return p; @@ -175,14 +170,14 @@ vec3 random_in_unit_sphere(int32_t thread_id) } // Returns a normalized version of the above vector -vec3 random_unit_vector(int32_t thread_id) +vec3 random_unit_vector() { - return normalize(random_in_unit_sphere(thread_id)); + return normalize(random_in_unit_sphere()); } -vec3 random_in_hemisphere(const vec3& normal, int32_t thread_id) +vec3 random_in_hemisphere(const vec3& normal) { - vec3 in_unit_sphere = random_in_unit_sphere(thread_id); + vec3 in_unit_sphere = random_in_unit_sphere(); if (dot(in_unit_sphere, normal) > 0.0) return in_unit_sphere; @@ -196,19 +191,19 @@ vec3 reflect(const vec3& v, const vec3 n) return v - 2*dot(v,n)*n; } -vec3 refract(const vec3& uv, const vec3& n, float etai_over_etat) +vec3 refract (const vec3& uv, const vec3& n, double etai_over_etat) { - float cos_theta = fmin(dot(-uv, n), 1.0); + double cos_theta = fmin(dot(-uv, n), 1.0); vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n); vec3 r_out_parallel = -sqrt(fabs(1.0 - r_out_perp.length_squared())) * n; return r_out_perp + r_out_parallel; } -vec3 random_in_unit_disk(int32_t thread_id) +vec3 random_in_unit_disk() { while (true) { - auto p = vec3(random_float(-1,1,thread_id), random_float(-1,1,thread_id), 0); + auto p = vec3(random_double(-1,1), random_double(-1,1), 0); if (p.length_squared() >= 1) continue; return p; }