From 4d9487813bc798b734e4b5a00674dd311bbeac0f Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Tue, 20 Jan 2026 13:20:17 +0800 Subject: [PATCH] doc: migrate all old doc --- doc/src/carton/arg_parser.dox | 200 ----------------- doc/src/carton/binstore.dox | 208 ++++++++++++++++++ doc/src/carton/clap.dox | 187 ++++++++++++++++ doc/src/carton/config_manager.dox | 151 ------------- .../{exception_helper.dox => ironpad.dox} | 62 +++--- doc/src/index.dox | 14 +- doc/src/string/op.dox | 2 +- doc/src/windows/dialog.dox | 8 +- src/yycc/carton/csconsole.hpp | 2 +- src/yycc/carton/fft.hpp | 2 +- src/yycc/carton/ironpad.hpp | 2 +- 11 files changed, 437 insertions(+), 401 deletions(-) delete mode 100644 doc/src/carton/arg_parser.dox create mode 100644 doc/src/carton/binstore.dox create mode 100644 doc/src/carton/clap.dox delete mode 100644 doc/src/carton/config_manager.dox rename doc/src/carton/{exception_helper.dox => ironpad.dox} (63%) diff --git a/doc/src/carton/arg_parser.dox b/doc/src/carton/arg_parser.dox deleted file mode 100644 index 3d20f15..0000000 --- a/doc/src/carton/arg_parser.dox +++ /dev/null @@ -1,200 +0,0 @@ -namespace YYCC::ArgParser { -/** - -\page arg_parser Universal Argument Parser - -YYCC::ArgParser provides an universal way to parsing command line arguments. - -Universal argument parser has similar design with universal config manager, -it is highly recommand that read \ref config_manager chapter first, -because you will have a clear understanding of this namespace after reading universal config manager chapter. - -There is an example about how to use universal argument parser. -In following content, we will describe it in detail. - -\code{.cpp} -class TestArgParser { -public: - TestArgParser() : - m_IntArgument(YYCC_U8("int"), YYCC_U8_CHAR('i'), YYCC_U8("integral argument"), YYCC_U8("114514")), - m_FloatArgument(nullptr, YYCC_U8_CHAR('f'), nullptr, nullptr, true), - m_StringArgument(YYCC_U8("string"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true), - m_BoolArgument(nullptr, YYCC_U8_CHAR('b'), nullptr), - m_ClampedFloatArgument(YYCC_U8("clamped-float"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true, YYCC::Constraints::GetMinMaxRangeConstraint(-1.0f, 1.0f)), - m_OptionContext(YYCC_U8("TestArgParser"), YYCC_U8("This is the test of argument parser."), { - &m_IntArgument, &m_FloatArgument, &m_StringArgument, - &m_BoolArgument, &m_ClampedFloatArgument - }) {} - ~TestArgParser() {} - - YYCC::ArgParser::NumberArgument m_IntArgument; - YYCC::ArgParser::NumberArgument m_FloatArgument; - YYCC::ArgParser::StringArgument m_StringArgument; - - YYCC::ArgParser::SwitchArgument m_BoolArgument; - YYCC::ArgParser::NumberArgument m_ClampedFloatArgument; - - YYCC::ArgParser::OptionContext m_OptionContext; -}; - -// Initialize argument parser. -TestArgParser test; -// Get argument list for parsing from standard C main function. -auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(argc, argv); -// Start parsing -test.Parse(al); -// Get captured string argument -if (test.m_StringArgument.IsCaptured()) - auto val = test.m_StringArgument.Get(); -\endcode - -These code can resolve following command line: - -\code{.sh} -exec -i 114514 -f 2.0 --string fuck -b --clamped-float 0.5 -\endcode - -For convenience, we define following terms used in this article. - -\li Every items in command line: Argument. -\li \c -i, \c --clamped-float: \b Switch / \b Option. the argument starts with dash or double dash. -\li \c 114514: \b Value. the value of switch. - -\section arg_parser__argument Argument - -Argument is the leaf of argument parser. -It has the same position as setting in universal config manager. - -\subsection arg_parser__argument__presets Argument Presets - -Like setting in universal config manager, -we also provide various common used argument presets. -Current'y we support following argument presets: - -\li NumberArgument: The argument storing arithmetic type (except \c bool) inside. Such as -i 114514 in example. -\li StringArgument: The argument storing string inside. Such as --string fuck in example. -\li SwitchArgument: The argument storing nothing. It is just a simple switch. Such as -b in example. - -When constructing these argument, -you need provide one from long name or short name, or both of them. -Short name is the argument starting with dash and long name starts with double dash. -You don't need add dash or double dash prefix when providing these names. -Please note only ASCII characters, which can be displayed on screen, can be used in these names. - -Optionally, you can provide description when constructing, -which will tell user how this switch does and more infomation about this switch. -And, you can add an example to tell user which value is valid. - -Next, you can specify an argument to be optional. -Optional argument can be absent in command line. -Oppositely, non-optional argument must be presented in command line, -otherwise parser will return false to indicate an error. -For checking whether an optional argument is specified, -please call AbstractArgument::IsCaptured(). - -Last, you can optionally assign a constraint to it, -to help argument limit its value. - -However SwitchArgument must be optional argument. -Because it is true if user specify it explicit it, -and will be false if user do not give this flag. -SwitchArgument doesn't have constraint features, -because it doesn't store any value inside. -Thus no need to limit this. - -\subsection arg_parser__argument__custom Custom Argument - -In most cases, the combination use of argument presets and constraints is enough. -However, if you still are urge to create your personal argument, -please inherit AbstractArgument and implement essential class functions. -For the class functions you need to implement, -please refer to our argument presets. - -\section arg_parser__argument_list Argument List - -Argument list is a struct used by parser for parsing. -It is a higher wrapper of a simple list containing argument items. -We provide 2 ways to get argument list. - -\li ArgumentList::CreateFromStd: Create argument list from standard C main function parameters. -\li ArgumentList::CreateFromWin32: Create argument list from Win32 functions in Windows. -You should use this function in Windows instead of ArgumentList::CreateFromStd. -Because the command line passed in standard C main function has encoding issue in Windows. -Use this function you will fetch correct argument list especially command including non-ASCII characters. - -Please note the first argument in given command line will be stripped. -Because in most cases it point to the executable self, -and should not be seen as the part of argument list. - -\section arg_parser__option_context Option Context - -Please note any unknow argument will let the parser return false. -This is different with other argument parsers. -In other common argument parsers, -they will collect all unknow argument as positional argument, -or just simply ignore them. - -OptionContext also will not add \c -h or \c --help switch automatically. -This is also differnent with other parsers. -You should manually add it. -However, OptionContext provide a universal help print function, OptionContext::Help. -You can directly call it to output help text if you needed (fail to parse or user order help). - -\section arg_parser__limitation Limitation - -This universal argument parser is a tiny parser. -It only just fulfill my personal requirements. -So it only accepts limited command line syntax. -In following content I will tell you some syntaxes which this parser \b not accept. - -\subsection arg_parser__limitation__flag_combination Flag Combination - -\code{.sh} -exec -l -s -h -exec -lsh -\endcode - -Parser accept first line but not accept the second line. -You must write these flags independently. - -\subsection arg_parser__limitation__equal_symbol Equal Symbol - -\code{.sh} -exec --value 114514 -exec --value=114514 -exec --value:114514 -\endcode - -Parser only accept first line command. -You can not use equal symbol or any other symbol to assign value for specified argument. -You must write value after the argument immediately please. - -\subsection arg_parser__limitation__variable_argument Variable Argument - -\code{.sh} -exec -DSOME_VARABLE=SOME_VALUE -exec -D SOME_VARIABLE=SOME_VALUE -\endcode - -Parser only accept second line. -However you nned to write a custom argument or constraint to holding this value. - -\subsection arg_parser__limitation__switch_dependency Switch Dependency - -\code{.sh} -exec --action-a --action-b -\endcode - -For command line written above, -if you hope \c --action-a and \c --action-b is exclusive, -or \c --action-b only be valid if \c --action-a specified, -you should manually implement this. -Parser don't have such features to process this switch dependency. - -The thing you need to do is set these switches are \b not optional. -And after parser do a success parsing, -manually calling AbstractArgument::IsCaptured to fetch whether corresponding switches are captured, -then do your personal dependency check. - -*/ -} \ No newline at end of file diff --git a/doc/src/carton/binstore.dox b/doc/src/carton/binstore.dox new file mode 100644 index 0000000..d826124 --- /dev/null +++ b/doc/src/carton/binstore.dox @@ -0,0 +1,208 @@ +namespace yycc::carton::binstore { +/** + +\page binstore Binary Settings Storage (Binstore) + +The binstore module provides a binary settings storage system that allows +applications to persistently store and retrieve configuration settings in +a binary format. It includes functionality for type-safe serialization and deserialization, +setting management with unique tokens for access control, version control with migration strategies, +and comprehensive error handling. + +\section binstore__overview Overview + +The binstore module consists of several key components: + +\li types: Basic types and error handling for the module +\li serdes: Serialization/deserialization functionality for different data types +\li setting: Management of settings with name-based lookup and token-based access +\li configuration: Version and settings collection management +\li storage: Main storage class for loading/saving settings to/from files or streams + +\section binstore__example Example Usage + +Here is a complete example showing how to use the binstore module: + +\code{.cpp} +#include +#include +#include +#include +#include + +using namespace yycc::carton::binstore; +using namespace yycc::patch::stream; + +enum class LogLevel : uint8_t { Debug, Info, Warning, Error }; + +int main() { + // Create settings collection + auto settings = setting::SettingCollection(); + auto int_setting_token = settings.add_setting(setting::Setting(u8"max_connections")); + auto float_setting_token = settings.add_setting(setting::Setting(u8"timeout")); + auto string_setting_token = settings.add_setting(setting::Setting(u8"server_address")); + auto bool_setting_token = settings.add_setting(setting::Setting(u8"enable_logging")); + auto enum_setting_token = settings.add_setting(setting::Setting(u8"log_level")); + + // Create configuration with version 1 + auto config = configuration::Configuration(1, std::move(settings)); + + // Create storage with the configuration + auto storage = storage::Storage(std::move(config)); + + // Using appropriate SerDes types for different data types + using IntSerDes = serdes::IntegralSerDes; + using FloatSerDes = serdes::FloatingPointSerDes; + using StringSerDes = serdes::StringSerDes; + using BoolSerDes = serdes::BoolSerDes; // true as default value + using EnumSerDes = serdes::EnumSerDes; + + // Set values + storage.set_value(int_setting_token, 100); + storage.set_value(float_setting_token, 2.5f); + storage.set_value(string_setting_token, u8"localhost"); + storage.set_value(bool_setting_token, true); + storage.set_value(enum_setting_token, LogLevel::Debug); + + // Save to file + if (auto result = storage.save_into_file("config.bin"); result.has_value()) { + std::cout << "Configuration saved successfully" << std::endl; + } else { + std::cout << "Failed to save configuration" << std::endl; + } + + // Load from file + auto new_config = configuration::Configuration(1, setting::SettingCollection()); + auto new_storage = storage::Storage(std::move(new_config)); + + if (auto result = new_storage.load_from_file("config.bin", storage::LoadStrategy::MigrateOld); result.has_value()) { + std::cout << "Configuration loaded successfully" << std::endl; + + // Get values + int32_t max_conn = new_storage.get_value(int_setting_token); + float timeout = new_storage.get_value(float_setting_token); + std::u8string addr = new_storage.get_value(string_setting_token); + bool logging = new_storage.get_value(bool_setting_token); + LogLevel level = new_storage.get_value(enum_setting_token); + + std::cout << "Max connections: " << max_conn << std::endl; + std::cout << "Timeout: " << timeout << std::endl; + std::cout << "Server address: " << addr << std::endl; + std::cout << "Logging enabled: " << (logging ? "yes" : "no") << std::endl; + std::cout << "Log level: " << static_cast(level) << std::endl; + } else { + std::cout << "Failed to load configuration" << std::endl; + } + + return 0; +} +\endcode + +\section binstore__components Components + +\subsection binstore__settings Settings Management + +Settings are identified by unique names and accessed via tokens. The [SettingCollection](\ref setting::SettingCollection) +manages a collection of settings and ensures no duplicates. + +\subsection binstore__configuration Configuration + +The [Configuration](\ref configuration::Configuration) class holds the version identifier and the collection of settings. +Version control is crucial for handling configuration migration between application versions. + +\subsection binstore__storage Storage + +The [Storage](\ref storage::Storage) class is the main interface for setting/getting values and loading/saving configurations. +It provides methods for both file-based and stream-based operations. + +\subsection binstore__serdes Serialization/Deserialization + +SerDes (Serializer/Deserializer) classes handle type-safe conversion between values and their binary representation. +Built-in SerDes types include: + +\li Integral types ([IntegralSerDes](\ref serdes::IntegralSerDes)) +\li Floating-point types ([FloatingPointSerDes](\ref serdes::FloatingPointSerDes)) +\li String types ([StringSerDes](\ref serdes::StringSerDes)) +\li Boolean types ([BoolSerDes](\ref serdes::BoolSerDes)) +\li Enum types ([EnumSerDes](\ref serdes::EnumSerDes)) + +For some of them, you can specify value range and default value via template parameters. + +\section binstore__load_strategies Load Strategies + +The binstore module provides different strategies for handling version mismatches: + +\li [OnlyCurrent](\ref storage::LoadStrategy::OnlyCurrent): Only accept configurations with matching version +\li [MigrateOld](\ref storage::LoadStrategy::MigrateOld): Accept matching and older versions, reject newer versions +\li [AcceptAll](\ref storage::LoadStrategy::AcceptAll): Accept all versions (not recommended for production) + +\section binstore__custom_serdes Custom SerDes + +Custom SerDes (Serializer/Deserializer) can be created by implementing the \c SerDes concept. +A valid SerDes must satisfy the following requirements: + +\li Have a type alias called \c ValueType indicating the corresponding setting type +\li Have a member function called \c serialize that accepts a const reference of the setting data and returns \c ByteArray +or \c std::nullopt if serialization fails. +\li Have a member function called \c deserialize that converts \c ByteArray to the desired type +or returns \c std::nullopt if deserialization fails. +\li Have a member function called \c reset that returns a default \c ByteArray value. + +Here is an example of a custom SerDes for storing IPv4 addresses: + +\code{.cpp} +#include +#include + +struct IPv4Address { + std::uint8_t octets[4]; + + IPv4Address() : octets{0, 0, 0, 0} {} + IPv4Address(std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) { + octets[0] = a; octets[1] = b; octets[2] = c; octets[3] = d; + } +}; + +struct IPv4SerDes { + using ValueType = IPv4Address; + static constexpr size_t VALUE_SIZE = sizeof(IPv4Address); // 4 octets + + std::optional serialize(const ValueType& value) const { + types::ByteArray ba; + ba.resize_data(VALUE_SIZE); + std::memcpy(ba.get_data_ptr(), value.octets, VALUE_SIZE); + return ba; + } + + std::optional deserialize(const types::ByteArray& ba) const { + if (ba.get_data_size() != VALUE_SIZE) return std::nullopt; + + ValueType value; + std::memcpy(value.octets, ba.get_data_ptr(), VALUE_SIZE); + return value; + } + + types::ByteArray reset() const { + // Reset to local address + ValueType default_value(127, 0, 0, 1); + return this->serialize(default_value).value(); + } +}; +\endcode + +To use the custom SerDes: + +\code{.cpp} +// Add setting to collection +auto ip_setting_token = settings.add_setting(setting::Setting(u8"server_ip")); + +// Use custom SerDes +IPv4SerDes ip_serdes; +storage.set_value(ip_setting_token, IPv4Address(192, 168, 1, 1)); + +// Retrieve value +IPv4Address ip_addr = storage.get_value(ip_setting_token); +\endcode + +*/ +} \ No newline at end of file diff --git a/doc/src/carton/clap.dox b/doc/src/carton/clap.dox new file mode 100644 index 0000000..ec99e6a --- /dev/null +++ b/doc/src/carton/clap.dox @@ -0,0 +1,187 @@ +namespace yycc::carton::clap { +/** + +\page clap Command Line Argument Parser (CLAP) + +Command Line Argument Parser (CLAP) module for handling command line arguments and environment variables. +This module provides a comprehensive system for defining, parsing, and validating command line +arguments and environment variables. It includes components for defining application metadata, +command line options, variables, and utilities for parsing and validation. + +\section clap__overview Overview + +The CLAP module consists of several key components: + +\li Types: Error types and result types used throughout the module +\li Validator: Type-safe validation for command line argument values +\li Option: Command line options with short and long names +\li Variable: Environment variables that can be captured +\li Summary: Application metadata (name, version, author, description) +\li Application: Complete application definition with options and variables +\li Manual: Help and version information generation +\li Parser: Command line argument parsing functionality +\li Resolver: Environment variable resolution functionality + +\section clap__example Example Usage + +Here is a complete example showing how to use the CLAP module: + +\code{.cpp} +#include +#include +#include +#include + +using namespace yycc::carton::clap; +using namespace yycc::patch::stream; + +// Define an application with options and variables +int main(int argc, char* argv[]) { + // Create application summary + auto summary = summary::Summary(u8"MyApp", u8"author", u8"1.0.0", u8"A sample application"); + + // Create options collection + auto options = option::OptionCollection(); + auto int_opt = options.add_option(option::Option(u8"i", u8"int", u8"NUM", u8"integral argument")); + auto float_opt = options.add_option(option::Option(u8"f", std::nullopt, u8"NUM", u8"floating point argument")); + auto string_opt = options.add_option(option::Option(std::nullopt, u8"string", u8"STR", u8"string argument")); + auto flag_opt = options.add_option(option::Option(u8"v", std::nullopt, std::nullopt, u8"verbose mode")); + + // Create variables collection + auto variables = variable::VariableCollection(); + auto env_var = variables.add_variable(variable::Variable(u8"ENV_VAR", u8"Environment variable description", true)); + + // Create the application and manual + auto app = application::Application(std::move(summary), std::move(options), std::move(variables)); + auto manual = manual::Manual(app); + + // Parse command line arguments + auto result = parser::Parser::from_system(app); + if (result.has_value()) { + auto parser = std::move(result.value()); + + // Get values using validators + using IntValidator = validator::IntegralValidator; + using FloatValidator = validator::FloatingPointValidator; + using StringValidator = validator::StringValidator; + + // Check and get integer option + if (auto int_val = parser.get_value_option(int_opt); int_val.has_value()) { + std::cout << "Integer value: " << int_val.value() << std::endl; + } + + // Check and get float option + if (auto float_val = parser.get_value_option(float_opt); float_val.has_value()) { + std::cout << "Float value: " << float_val.value() << std::endl; + } + + // Check and get string option + if (auto str_val = parser.get_value_option(string_opt); str_val.has_value()) { + std::cout << "String value: " << str_val.value() << std::endl; + } + + // Check flag option + if (auto flag_val = parser.get_flag_option(flag_opt); flag_val.has_value() && flag_val.value()) { + std::cout << "Verbose mode enabled" << std::endl; + } + } else { + // Print help if parsing failed + manual.print_help(std::cout); + return 1; + } + + return 0; +} +\endcode + +This code handles command lines like: +\code{.sh} +./myapp -i 123 -f 2.5 --string "hello world" -v +\endcode + +\section clap__components Components + +\subsection clap__application Application Definition + +The [Application](\ref application::Application) class represents a complete command line application with its summary, options, and environment variables. +It combines the application metadata, command line options, and environment variables into a single unit. + +\subsection clap__options Options + +[Option](\ref option::Option) is command line arguments that can accept values or act as flags. +They can have both short names (single character) +and long names (full text). The [OptionCollection](\ref option::OptionCollection) manages a collection of options and ensures no duplicates. + +\subsection clap__variables Variables + +[Variable](\ref variable::Variable) represent environment variables that can be captured and validated. The [VariableCollection](\ref variable::VariableCollection) +manages a collection of environment variables and ensures no duplicates. + +\subsection clap__parsing Parsing + +The [Parser](\ref parser::Parser) class handles command line argument parsing. It can be created from user-provided arguments +or from system arguments (argc/argv). Values are retrieved using type-safe validators. + +\subsection clap__validation Validation + +Validators ensure type-safe validation of command line argument values. +The module provides built-in validators for: + +\li Integral types ([IntegralValidator](\ref validator::IntegralValidator)) +\li Floating-point types ([FloatingPointValidator](\ref validator::FloatingPointValidator)) +\li String types ([StringValidator](\ref validator::StringValidator)) + +For some of them, you also can specify value range via template arguments. + +\section clap__custom_validators Custom Validator + +Custom validators can be created by implementing the \c Validator concept. +A valid validator must satisfy the following requirements: + +\li Have a type alias called \c ReturnType indicating the return value type +\li Have a member function called \c validate that receives const std::u8string_view& as its only argument +and returns validated \c ReturnType or \c std::nullopt if validation fails + +Here is an example of a custom validator that validates email addresses: + +\code{.cpp} +#include +#include + +struct EmailValidator { + using ReturnType = std::u8string; + + std::optional validate(const std::u8string_view& sv) const { + // Simple email validation using regex + static const std::regex email_regex( + R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})"); + + auto email_str = yycc::string::reinterpret::as_ordinary_view(sv); + if (std::regex_match(email_str, email_regex)) { + return sv; + } + return std::nullopt; + } +}; +\endcode + +To use the custom validator: + +\code{.cpp} +// Add option to application +auto email_opt = options.add_option(option::Option(std::nullopt, u8"email", u8"EMAIL", u8"Email address")); + +// Use custom validator +if (auto email_val = parser.get_value_option(email_opt); email_val.has_value()) { + std::cout << yycc::patch::format(u8"Valid email: {}", email_val); << std::endl; +} +\endcode + +\section clap__limitations Limitations + +Due to the limitations of implementation, +CLAP now only allow only zero or one associated value for single option. +More than one assocciated value for single option is not supported. + +*/ +} \ No newline at end of file diff --git a/doc/src/carton/config_manager.dox b/doc/src/carton/config_manager.dox deleted file mode 100644 index f5b430c..0000000 --- a/doc/src/carton/config_manager.dox +++ /dev/null @@ -1,151 +0,0 @@ -namespace YYCC::ConfigManager { -/** - -\page config_manager Universal Config Manager - -YYCC::ConfigManager give programmer an universal way to manage its program settings. -There is an example about how to use universal config manager. -In following content, we will describe it in detail. - -\code -class TestConfigManager { -public: - enum class TestEnum : int8_t { - Test1, Test2, Test3 - }; - - TestConfigManager() : - m_IntSetting(YYCC_U8("int-setting"), INT32_C(0)), - m_StringSetting(YYCC_U8("string-setting"), YYCC_U8("")), - m_FloatSetting(YYCC_U8("float-setting"), 0.0f, YYCC::Constraints::GetNumberRangeConstraint(-1.0f, 1.0f)), - m_EnumSetting(YYCC_U8("enum-setting"), TestEnum::Test1), - m_CoreManager(YYCC_U8("test.cfg"), UINT64_C(0), { - &m_IntSetting, &m_StringSetting, &m_FloatSetting, &m_EnumSetting - }) - {} - ~TestConfigManager() {} - - YYCC::ConfigManager::NumberSetting m_IntSetting; - YYCC::ConfigManager::StringSetting m_StringSetting; - YYCC::ConfigManager::NumberSetting m_FloatSetting; - YYCC::ConfigManager::NumberSetting m_EnumSetting; - - YYCC::ConfigManager::CoreManager m_CoreManager; -}; - -// Initialize config manager -TestConfigManager test; -// Load settings. -test.m_CoreManager.Load() -// Get string setting value. -auto val = test.m_StringSetting.Get(); -\endcode - -\section config_manager__setting Setting - -Setting can be seen as the leaf of the config tree. -Each setting describe a single configuration entry. - -\subsection config_manager__setting__presets Setting Presets - -We currently provide 2 setting preset classes which you can directly use. - -\li NumberSetting: The setting storing a number inside. -It is a template class. Support all arithmetic and enum types (integral, floating point, bool, enum). -\li StringSetting: The setting storing a string inside. - -When constructing these settings, -you need to provide its unique name which will be used when saving to file or reading from file. -Also you need to provide a default value for it. -It will be used when fail to read file or initializing itself. - -Optionally, you also can provide a constraint to setting. -Constraint is the struct instructing library to limit value in specified range. -It usually is used for making sure the setting stored value is valid. -See \ref constraints chapters to know how we provide constraints. - -\subsection config_manager__setting__custom Custom Setting - -In most cases, the combination use of setting presets and constraints is enough. -However, if you still are urge to create your personal setting, -please inherit AbstractSetting and implement essential class functions. -For the class functions you need to implement, -please refer to our setting presets, NumberSetting and StringSetting. - -\section config_manager__core_manager Core Manager - -CoreManager manage a collection of settings. -And have responsibility to reading and writing config file. - -We highly suggest that you create a personal config manager class like example does. -Then put essential settings and core manager inside it. -Please note you must place core manager after all settings. -Because the order of C++ initializing its class member is the order you declared them. -The constructor of core manager need the pointer to all it managed settings, -so it must be initialized after initializing all settings. - -When initializing core manager, you need assign config file path first. -Then you need specify a version number. -Version number is important. -It will be used when reading config file and only can be increased if needed (version can not downgrade). -The last argument is an initializer list which contain the \b pointer to all settings this manager managed. - -When executing YYCC::ConfigManager::CoreManager::Load to load configs, it will perform following steps one by one: - -
    -
  • - Open given config file. -
      -
    • - If given file is not existing, loading function will simply return and all configs will be reset to its default value. -
    • -
    • - Success to open file, go to next step. -
    • -
    -
  • - -
  • - Fetch version number from file. -
      -
    • - If fail to read version number from file, loading function will simply return and all configs will be reset to its default value. -
    • -
    • - If the version of config file is higher than your specified version number when constructing this class, - core manager will assume you are trying to read a config file created by a higher version program, - and will reject reading and use default value for all settings. -
    • -
    • - If the version of config file is lower than your specified version number, - core manager will try to read config file and do proper migration (set default value for configs which do not existing) if possible. -
    • -
    • - If the version of config file is equal than your specified version number, - core manager will read config file normally. -
    • -
    -
  • - -
  • - Read config file body. -
      -
    • - If any IO error occurs when reading, loading function will simply return. - All read config will keep their read value and all configs which has not been read will keep their default value. -
    • -
    • - If some config can not parse binary data to its type, - this config will be skipped and core manager will process next config. - This config will keep its default value. -
    • -
    -
  • -
- -All of these scenarios can be found by the return value of loading function. -The return type of loading function, ConfigLoadResult is a flag enum. -You can find whether loading process happend specified issue by using bitwise operation on it. - -*/ -} \ No newline at end of file diff --git a/doc/src/carton/exception_helper.dox b/doc/src/carton/ironpad.dox similarity index 63% rename from doc/src/carton/exception_helper.dox rename to doc/src/carton/ironpad.dox index 553a2c3..8669a2b 100644 --- a/doc/src/carton/exception_helper.dox +++ b/doc/src/carton/ironpad.dox @@ -1,30 +1,30 @@ -namespace YYCC::ExceptionHelper { +namespace yycc::carton::ironpad { /** -\page exception_helper Unhandled Exception Handler +\page ironpad Unhandled Exception Handler -Most Linux users are familiar with core dump. -However core dump is a tough work on Windows especially most Windows users are naive for getting core dump. -So it is essential to make an easy-to-visit core dump Feature for Windows program. -YYCC provides this feature in YYCC::ExceptionHelper. +Most Linux users are familiar with using core dump to find bugs. +However finding bugs is a tough work on Windows especially most Windows users are naive for getting core dump. +So it is essential to make an easy-to-visit core dump feature for Windows program. +This is the reason why I create this module, yycc::carton::ironpad. You may know Google also has a similar and universal project called Crashpad used by Google Chrome. That's right. But it is too heavy. I just want to implement a tiny but worked core dump feature on Windows. This module is Windows specific. -It will be invisible on other platforms. +It still be available on other operating systems but all of its functions are do nothing. -\section exception_helper__usage Usage +\section ironpad__usage Usage -\subsection exception_helper__usage__code Register Code +\subsection ironpad__usage__code Register Code -In most scenarios, programmer only need call #Register when program started or module loaded. -And call #Unregister when program exited or module unloaded. +In most scenarios, programmer only need call #startup when program started or module loaded. +And call #shutdown when program exited or module unloaded. All details are hidden by these 2 feature. Programmer do not need worried about the implementation of unhandled exception handler. -Optionally, you can provide a function pointer during calling #Register as a callback. +Optionally, you can provide a function pointer during calling #startup as a callback. The prototype of this function pointer is #ExceptionCallback. This callback will be called if any unhandled exception happened. It provides 2 pathes to log file and core dump file respectively. @@ -35,21 +35,21 @@ However, please note the pathes provided by callback may be empty. In this case, it means that handler fail to create corresponding log files. Also, if you trying to register unhandled exception handler on the same process in different module with different callback, only the callback provided in first success registering will be called when unhandled exception happened, -due to \ref exception_helper__notes__singleton design. +due to \ref ironpad__notes__singleton design. -\subsection exception_helper__usage__location Location +\subsection ironpad__usage__location Location When unhandled exception occurs, unhandled exception handler will try to record error log and core dump in following path: -\li Error Log: \%LOCALAPPDATA\%\\CrashDumps\\program.exe.pid.log -\li Core Dump: \%LOCALAPPDATA\%\\CrashDumps\\program.exe.pid.dmp +\li Error Log: \%LOCALAPPDATA\%\\IronPad\\program.exe.pid.log +\li Core Dump: \%LOCALAPPDATA\%\\IronPad\\program.exe.pid.dmp The italic characters program.exe and pid will be replaced by program name and process ID respectively at runtime. -Directory \%LOCALAPPDATA\%\\CrashDumps also is Windows used crash dump directory. -So you may see some other core dumps done by Windows in it. +Directory \%LOCALAPPDATA\%\\IronPad is the dedicated directory for this module. +So you may see the generated logs and dumps in it. -\subsection exception_helper__usage__last_remedy Last Remedy +\subsection ironpad__usage__last_remedy Last Remedy If unhandled exception handler occurs error, these stuff may not be generated correctly. The end user may not find them and send them to you. @@ -65,40 +65,40 @@ Also please note the last remedy may still have a little bit possibility to occu especially the error occurs in back trace function. There is no guaranteen that unhandled exception handler must generate error log and core dump. -\section exception_helper__notes Notes +\section ironpad__notes Notes -\subsection exception_helper__notes__thread_safe Thread Safe +\subsection ironpad__notes__thread_safe Thread Safe -All exposed functions in YYCC::ExceptionHelper are thread safe. -The implementation uses \c std:mutex to ensure this. +All exposed functions in this namespace are thread safe. +The implementation uses \c std::mutex to ensure this. -\subsection exception_helper__notes__singleton Singleton Handler +\subsection ironpad__notes__singleton Singleton Handler -YYCC::ExceptionHelper also have a mechanism that make sure the same unhandled exception handler implementation only appear once in the same process. +This namespace also have a mechanism that make sure the same unhandled exception handler implementation only appear once in the same process. For example, you have an executable program A.exe, and 2 dynamic libraries B.dll and C.dll. A.exe and B.dll use YYCC unhandled exception handler feature but C.dll not. A.exe will load B.dll and C.dll at runtime. -Although both A.exe and B.dll call #Register, +Although both A.exe and B.dll call #startup, when unhandled exception occurs, there is only one error report output, which may be generated by A.exe or B.dll accoridng to their order of loading. The core purpose of this is making sure the program will not output too many error report for the same unhandled exception, -no matter how many modules calling #Register are loaded. +no matter how many modules calling #startup are loaded. Only one error report is enough. More precisely, we use \c CreateMutexW to create an unique mutex in Windows global scope, -to make sure #Register only run once in the same process. +to make sure #startup only run once in the same process. It is very like the implementation of singleton application. -\subsection exception_helper__notes__recursive_calling Recursive Calling +\subsection ironpad__notes__recursive_calling Recursive Calling The implementation of unhandled exception handler may also will throw exception. This will cause infinite recursive calling. -YYCC::ExceptionHelper has internal mechanism to prevent this bad case. +This namespace has internal mechanism to prevent this bad case. If this really happened, the handler will quit silent and will not cause any issue. Programmer don't need to worry about this. -\subsection exception_helper__notes__user_callback The Timing of User Callback +\subsection ironpad__notes__user_callback The Timing of User Callback The timing of calling user callback is the tail of unhandled exception handler. It means that all log and coredump have been written if possible before calling callback. diff --git a/doc/src/index.dox b/doc/src/index.dox index a141b7b..d1cc1dd 100644 --- a/doc/src/index.dox +++ b/doc/src/index.dox @@ -64,19 +64,11 @@ \li \subpage csconsole - + \li \subpage binstore Windows Specific Features diff --git a/doc/src/string/op.dox b/doc/src/string/op.dox index 4b433ec..561d45b 100644 --- a/doc/src/string/op.dox +++ b/doc/src/string/op.dox @@ -162,7 +162,7 @@ std::vector split_owned(const std::u8string_view& strl, const std All these overloads take a string view as the first argument representing the string need to be split. The second argument is a string view representing the delimiter for splitting. -The first function #lazy_split returns a #LazySplit object that can be used in range-based for loops. +The first function #lazy_split returns a LazySplit object that can be used in range-based for loops. This is lazy-computed and memory-efficient for large datasets. The second function #split returns a vector of string views, which is memory-efficient but the views are only valid as long as the original string remains valid. diff --git a/doc/src/windows/dialog.dox b/doc/src/windows/dialog.dox index d1ee675..1cdebc2 100644 --- a/doc/src/windows/dialog.dox +++ b/doc/src/windows/dialog.dox @@ -133,10 +133,10 @@ auto result4 = open_folder(params); There are 4 file dialogs you can choose: -\li #open_file: Open single file -\li #open_files: Open multiple files -\li #save_file: Save single file -\li #open_folder: Open single directory +\li open_file(): Open single file +\li open_files(): Open multiple files +\li save_file(): Save single file +\li open_folder(): Open single directory \subsection windows__dialog__result__arguments Arguments diff --git a/src/yycc/carton/csconsole.hpp b/src/yycc/carton/csconsole.hpp index 7b7024e..1873247 100644 --- a/src/yycc/carton/csconsole.hpp +++ b/src/yycc/carton/csconsole.hpp @@ -25,7 +25,7 @@ * \li https://stackoverflow.com/questions/45575863/how-to-print-utf-8-strings-to-stdcout-on-windows * \li https://stackoverflow.com/questions/69830460/reading-utf-8-input * - * For how to utilize this functions provided by this namespace, please view \ref console_helper. + * For how to utilize this functions provided by this namespace, please view \ref csconsole. * * @warning * All functions provided by this namespace are too aggressive. diff --git a/src/yycc/carton/fft.hpp b/src/yycc/carton/fft.hpp index 15bb7fd..28e9f9f 100644 --- a/src/yycc/carton/fft.hpp +++ b/src/yycc/carton/fft.hpp @@ -248,7 +248,7 @@ namespace yycc::carton::fft { * @param[out] freq_scope The length of this data must be N / 2. * The first data is 0Hz and the frequency of last data is decided by sample rate which can be computed by get_max_freq() function in this class. * @param[in] window The window instance applied to data. - * @warnings + * @warning * This function is \b NOT thread-safe. * Please do NOT call this function in different thread for one instance. */ diff --git a/src/yycc/carton/ironpad.hpp b/src/yycc/carton/ironpad.hpp index 91bf81e..d139d00 100644 --- a/src/yycc/carton/ironpad.hpp +++ b/src/yycc/carton/ironpad.hpp @@ -8,7 +8,7 @@ * @details * This namespace is currently works on Windows. * On other platforms, this namespace provided functions do nothing. - * For how to utilize this namespace, please see \ref exception_helper. + * For how to utilize this namespace, please see \ref ironpad. * * This feature is originate from my created Virtools plugin. * Because its user frequently trigger some weird behaviors but I have no idea about the detail of them.