Skip to content
Snippets Groups Projects
Commit 8fd42a13 authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Added CliOptionGroup. Improved help print.

parent 77009612
Branches
No related tags found
No related merge requests found
...@@ -173,12 +173,15 @@ int main(azgra::i32 argc, const char **argv) ...@@ -173,12 +173,15 @@ int main(azgra::i32 argc, const char **argv)
'b', "bins", false, 10); 'b', "bins", false, 10);
azgra::cli::CliFlag flagVerbose("Verbose", "Make program output verbose.", 'v', "verbose"); azgra::cli::CliFlag flagVerbose("Verbose", "Make program output verbose.", 'v', "verbose");
azgra::cli::CliFlag flagGzipCompressionOption("GZIP", "gzip (zlib) compression", '\0', "gzip"); azgra::cli::CliFlag flagGzipCompressionOption("GZIP", "gzip (zlib) compression", '\0', "gzip");
azgra::cli::CliFlag flagLzmaCompressionOption("LZMA", "lzma compression", '\0', "lzma"); azgra::cli::CliFlag flagLzmaCompressionOption("LZMA", "lzma compression", '\0', "lzma");
azgra::cli::CliFlag flagBzip2CompressionOption("BZIP2", "bzip2 compression", '\0', "bzip2"); azgra::cli::CliFlag flagBzip2CompressionOption("BZIP2", "bzip2 compression", '\0', "bzip2");
azgra::cli::CliFlag flagB3dCompressionOption("B3D", "B3D cuda compression", '\0', "b3d"); azgra::cli::CliFlag flagB3dCompressionOption("B3D", "B3D cuda compression", '\0', "b3d");
azgra::cli::CliOptionGroup compressorGroup("CompressorGroup", {&flagGzipCompressionOption, &flagLzmaCompressionOption,
&flagBzip2CompressionOption, &flagB3dCompressionOption});
// Methods // Methods
azgra::cli::CliMethod methodVersion("version", azgra::cli::CliMethod methodVersion("version",
...@@ -188,42 +191,40 @@ int main(azgra::i32 argc, const char **argv) ...@@ -188,42 +191,40 @@ int main(azgra::i32 argc, const char **argv)
"Report information about loaded czi file."); "Report information about loaded czi file.");
azgra::cli::CliMethod methodDump("dump", azgra::cli::CliMethod methodDump("dump",
"Dump raw image data. [subblock]", "Dump raw image data.",
{&flagFolder}); {&flagFolder}, {&valFlagSubblock});
azgra::cli::CliMethod methodCompressionBenchmark("compressors-benchmark", azgra::cli::CliMethod methodCompressionBenchmark("compressors-benchmark",
"Compressors benchmark for subblocks in czi file. [compression-level] [subblock]" "Compressors benchmark for subblocks in czi file.",
" [compressor]", {&flagReportFile}, {&valFlagCompressionLevel, &valFlagSubblock, &compressorGroup});
{&flagReportFile});
azgra::cli::CliMethod methodFrameDiffCompression("frame-diff-compression", azgra::cli::CliMethod methodFrameDiffCompression("frame-diff-compression",
"Compress frames by their difference. [compression-level] [compressor]", "Compress frames by their difference.",
{&flagReportFile}); {&flagReportFile}, {&valFlagCompressionLevel, &compressorGroup});
azgra::cli::CliMethod methodFrameDiffHistogram("frame-diff-histogram", azgra::cli::CliMethod methodFrameDiffHistogram("frame-diff-histogram",
"Save histograms of frame differences. [compression-level] [bin-count]", "Save histograms of frame differences.",
{&flagFolder}); {&flagFolder}, {&valFlagCompressionLevel, &valFlagHistogramBinCount});
azgra::cli::CliMethod methodHistogram("histogram", azgra::cli::CliMethod methodHistogram("histogram",
"Save histograms of all frames or just one specific frame. [subblock] [bin-count]", "Save histograms of all frames or just one specific frame.",
{&flagFolder}); {&flagFolder}, {&valFlagSubblock, &valFlagHistogramBinCount});
azgra::cli::CliMethod methodCudaCompress("b3d", azgra::cli::CliMethod methodCudaCompress("b3d",
"Test only b3d compression. [subblock]", "Test only b3d compression.",
{&flagReportFile}); {&flagReportFile}, {&valFlagSubblock});
azgra::cli::CliMethod methodCudaCompressLossyTest("b3d-quantization-test", azgra::cli::CliMethod methodCudaCompressLossyTest("b3d-quantization-test",
"Test quantization steps of lossy compression. <report-file> <subblock>", "Test quantization steps of lossy compression.",
{&flagFolder, &flagReportFile}); {&flagFolder, &flagReportFile});
args.flags = {&flagCziFile, &flagFolder, &flagReportFile, &valFlagSubblock, &valFlagCompressionLevel, &valFlagHistogramBinCount, args.flags = {&flagCziFile, &flagFolder, &flagReportFile, &valFlagSubblock, &valFlagCompressionLevel, &valFlagHistogramBinCount,
&flagVerbose, &flagGzipCompressionOption, &flagLzmaCompressionOption, &flagBzip2CompressionOption, &flagVerbose};
&flagB3dCompressionOption}; args.add_group(compressorGroup);
args.methods = {&methodVersion, &methodReport, &methodDump, &methodCompressionBenchmark, &methodFrameDiffCompression, args.methods = {&methodVersion, &methodReport, &methodDump, &methodCompressionBenchmark, &methodFrameDiffCompression,
&methodFrameDiffHistogram, &methodHistogram, &methodCudaCompress, &methodFrameDiffHistogram, &methodHistogram, &methodCudaCompress,
&methodCudaCompressLossyTest}; &methodCudaCompressLossyTest};
if (!args.parse(argc, argv)) if (!args.parse(argc, argv))
{ {
fprintf(stderr, "%s\n", args.get_error().c_str()); fprintf(stderr, "%s\n", args.get_error().c_str());
......
...@@ -18,22 +18,33 @@ namespace azgra ...@@ -18,22 +18,33 @@ namespace azgra
class CliArguments class CliArguments
{ {
private: private:
const int FIRST_COLUMN_WIDTH = 30;
const int SECOND_COLUMN_WIDTH = 60;
std::stringstream errorStream; std::stringstream errorStream;
string::SmartStringView<char> appName; string::SmartStringView<char> appName;
string::SmartStringView<char> appDescription; string::SmartStringView<char> appDescription;
int outputWidth = 80; int outputWidth = 80;
bool someMethodMatched = false; bool someMethodMatched = false;
std::vector<CliOptionGroup> groups;
bool process_matched_flag(const string::SmartStringView<char> &match, bool shortMatch, const char **arguments, int &parseIndex); bool process_matched_flag(const string::SmartStringView<char> &match, bool shortMatch, const char **arguments, int &parseIndex);
bool process_matched_value_flag(CliOption *matchedFlag, const char *rawFlagValue); bool process_matched_value_flag(CliOption *matchedFlag, const char *rawFlagValue);
bool process_matched_method(const string::SmartStringView<char> &match); bool process_matched_method(const string::SmartStringView<char> &match);
bool process_multiflag(const string::SmartStringView<char> &match); bool process_multiflag(const string::SmartStringView<char> &match);
void print_flags(std::stringstream &outStream, const std::vector<CliOption *> &flags) const;
std::vector<CliOption*> get_flags_not_in_group() const;
public: public:
std::vector<CliMethod *> methods; std::vector<CliMethod *> methods;
std::vector<CliOption *> flags; std::vector<CliOption *> flags;
CliArguments(const string::SmartStringView<char> &name, const string::SmartStringView<char> &description, int width = 80); CliArguments(const string::SmartStringView<char> &name, const string::SmartStringView<char> &description, int width = 80);
void add_group(const CliOptionGroup &flagGroup);
bool parse(const int argc, const char **argv); bool parse(const int argc, const char **argv);
...@@ -42,6 +53,7 @@ namespace azgra ...@@ -42,6 +53,7 @@ namespace azgra
std::string get_error() const; std::string get_error() const;
bool is_any_method_matched() const; bool is_any_method_matched() const;
}; };
}; };
}; };
\ No newline at end of file
...@@ -16,11 +16,12 @@ namespace azgra ...@@ -16,11 +16,12 @@ namespace azgra
bool isMatched = false; bool isMatched = false;
bool isRequired = false; bool isRequired = false;
bool hasMatchCharacter = true; bool hasMatchCharacter = true;
bool isInGroup = false;
string::SmartStringView<char> name; string::SmartStringView<char> name;
string::SmartStringView<char> description; string::SmartStringView<char> description;
CliOption(const string::SmartStringView<char>& name, const string::SmartStringView<char>& description, CliOption(const string::SmartStringView<char> &name, const string::SmartStringView<char> &description,
char matchCharacter, const string::SmartStringView<char>& matchString, bool required = false) char matchCharacter, const string::SmartStringView<char> &matchString, bool required = false)
{ {
this->name = name; this->name = name;
this->description = description; this->description = description;
...@@ -48,12 +49,15 @@ namespace azgra ...@@ -48,12 +49,15 @@ namespace azgra
{ {
private: private:
std::vector<CliOption *> requiredFlags; std::vector<CliOption *> requiredFlags;
std::vector<CliOption *> optionalFlags;
public: public:
CliMethod(string::SmartStringView<char> methodMatchName, string::SmartStringView<char> description, CliMethod(string::SmartStringView<char> methodMatchName, string::SmartStringView<char> description,
const std::vector<CliOption *> &requiredFlags = std::vector<CliOption *>()) : const std::vector<CliOption *> &requiredFlags = std::vector<CliOption *>(),
const std::vector<CliOption *> &optionalFlags = std::vector<CliOption *>()) :
CliOption(methodMatchName, description, '\0', methodMatchName, false) CliOption(methodMatchName, description, '\0', methodMatchName, false)
{ {
this->requiredFlags = requiredFlags; this->requiredFlags = requiredFlags;
this->optionalFlags = optionalFlags;
hasMatchCharacter = false; hasMatchCharacter = false;
} }
...@@ -62,14 +66,19 @@ namespace azgra ...@@ -62,14 +66,19 @@ namespace azgra
return requiredFlags; return requiredFlags;
} }
std::vector<CliOption *> const &get_optional_flags() const
{
return optionalFlags;
}
}; };
class CliFlag : public CliOption class CliFlag : public CliOption
{ {
public: public:
CliFlag(const string::SmartStringView<char>& flagName, const string::SmartStringView<char>& description, char matchChar, CliFlag(const string::SmartStringView<char> &flagName, const string::SmartStringView<char> &description, char matchChar,
const string::SmartStringView<char>& matchString, bool required = false) : const string::SmartStringView<char> &matchString, bool required = false) :
CliOption(flagName, description, matchChar, matchString, required) CliOption(flagName, description, matchChar, matchString, required)
{ {
if (matchChar == '\0') if (matchChar == '\0')
...@@ -88,8 +97,8 @@ namespace azgra ...@@ -88,8 +97,8 @@ namespace azgra
private: private:
ValueType internalValue; ValueType internalValue;
public: public:
CliValueFlag(const string::SmartStringView<char>& flagName, const string::SmartStringView<char>& description, char matchChar, CliValueFlag(const string::SmartStringView<char> &flagName, const string::SmartStringView<char> &description, char matchChar,
const string::SmartStringView<char>& matchString, bool required = false, ValueType defaultValue = ValueType()) : const string::SmartStringView<char> &matchString, bool required = false, ValueType defaultValue = ValueType()) :
CliOption(flagName, description, matchChar, matchString, required) CliOption(flagName, description, matchChar, matchString, required)
{ {
internalValue = defaultValue; internalValue = defaultValue;
...@@ -104,5 +113,22 @@ namespace azgra ...@@ -104,5 +113,22 @@ namespace azgra
return internalValue; return internalValue;
} }
}; };
class CliOptionGroup : public CliOption
{
friend class CliArguments;
private:
//NOTE: We can have group rules. Like AtLeastOne, OnlyOne, All
std::vector<CliOption *> options;
public:
CliOptionGroup(const string::SmartStringView<char> &name, const std::vector<CliOption *> &flagsInGroup) :
CliOption(name, "", '\0', "", false)
{
hasMatchCharacter = false;
isRequired = false;
options = flagsInGroup;
}
};
}; };
}; };
\ No newline at end of file
...@@ -16,6 +16,7 @@ namespace azgra ...@@ -16,6 +16,7 @@ namespace azgra
class SimpleString class SimpleString
{ {
private: private:
bool _isEmpty = true;
/** /**
* @brief Internal string memory. * @brief Internal string memory.
*/ */
...@@ -73,6 +74,11 @@ namespace azgra ...@@ -73,6 +74,11 @@ namespace azgra
SimpleString(char *cString, const size_t length, bool noAlloc = false); SimpleString(char *cString, const size_t length, bool noAlloc = false);
public: public:
/**
* Empty string constructor.
*/
SimpleString();
/** /**
* @brief Construct a new Simple String object. * @brief Construct a new Simple String object.
* *
...@@ -80,6 +86,8 @@ namespace azgra ...@@ -80,6 +86,8 @@ namespace azgra
*/ */
SimpleString(const char *cString); SimpleString(const char *cString);
SimpleString(const std::vector<const char *> &strings);
~SimpleString(); ~SimpleString();
/** /**
...@@ -324,8 +332,10 @@ namespace azgra ...@@ -324,8 +332,10 @@ namespace azgra
bool operator==(const SimpleString &string) const; bool operator==(const SimpleString &string) const;
void operator+=(const char *cString); void operator+=(const char *cString);
void operator+=(const char c);
SimpleString operator+(const char *cString) const; SimpleString operator+(const char *cString) const;
SimpleString operator+(const char c) const;
/** /**
* @brief Create string by replicating. * @brief Create string by replicating.
...@@ -336,11 +346,11 @@ namespace azgra ...@@ -336,11 +346,11 @@ namespace azgra
*/ */
static SimpleString replicate(const char *cString, const azgra::i32 replicationCount); static SimpleString replicate(const char *cString, const azgra::i32 replicationCount);
void pad_left(const char padChar, const size_t padCount); void pad_left(const char padChar, const size_t desiredWidth);
void pad_right(const char padChar, const size_t padCount); void pad_right(const char padChar, const size_t desiredWidth);
void centerize(const char padChar, const size_t outputWidth); void centerize(const char padChar, const size_t desiredWidth);
}; };
}; // namespace string }; // namespace string
} // namespace azgra } // namespace azgra
...@@ -138,6 +138,83 @@ namespace azgra ...@@ -138,6 +138,83 @@ namespace azgra
return allFound; return allFound;
} }
std::vector<CliOption *> CliArguments::get_flags_not_in_group() const
{
std::vector<CliOption *> result;
for (CliOption *flag : flags)
{
if (!flag->isInGroup)
{
result.push_back(flag);
}
}
return result;
}
void CliArguments::print_flags(std::stringstream &outStream, const std::vector<CliOption *> &flagsToPrint) const
{
for (const CliOption *flag : flagsToPrint)
{
const char *req = (flag->isRequired ? "Required" : "Optional");
if (flag->hasMatchCharacter)
{
char matchCharString[2] = {flag->matchCharacter, '\0'};
string::SimpleString matcherString({"{-", matchCharString, ", --",
flag->matchString.data(), "} "});
matcherString.pad_right(' ', FIRST_COLUMN_WIDTH);
outStream << '\t' << matcherString.get_c_string();
}
else
{
string::SimpleString matcherString({"{--", flag->matchString.data(), "} "});
matcherString.pad_right(' ', FIRST_COLUMN_WIDTH);
outStream << '\t' << matcherString.get_c_string();
}
string::SimpleString flagNameDesc({flag->name.data(), " - ", flag->description.data()});
flagNameDesc.pad_right(' ', SECOND_COLUMN_WIDTH);
outStream << flagNameDesc.get_c_string() << " [" << req;;
auto *intFlag = dynamic_cast<const CliValueFlag<int> *> (flag);
if (intFlag)
outStream << ", int";
auto *uintFlag = dynamic_cast<const CliValueFlag<unsigned int> *> (flag);
if (uintFlag)
{
outStream << ", uint";
}
auto *floatFlag = dynamic_cast<const CliValueFlag<float> *> (flag);
if (floatFlag)
{
outStream << ", float";
}
auto *constCharFlag = dynamic_cast<const CliValueFlag<const char *> *> (flag);
if (constCharFlag)
{
outStream << ", const char*";
}
auto *stringFlag = dynamic_cast<const CliValueFlag<std::string> *> (flag);
if (stringFlag)
{
outStream << ", std::string";
}
outStream << "]" << std::endl;
}
}
bool CliArguments::parse(const int argc, const char **argv) bool CliArguments::parse(const int argc, const char **argv)
{ {
const char *helpIdentifier = "--help"; const char *helpIdentifier = "--help";
...@@ -234,65 +311,36 @@ namespace azgra ...@@ -234,65 +311,36 @@ namespace azgra
helpStream << "Methods:" << std::endl; helpStream << "Methods:" << std::endl;
for (const auto &method : methods) for (const auto &method : methods)
{ {
helpStream << "\t" << method->name.string_view() << " - " << method->description.string_view(); string::SimpleString methodName(method->name.data());
auto methodReqFlags = method->get_required_flags(); string::SimpleString methodDesc(method->description.data());
if (!methodReqFlags.empty()) methodName.pad_right(' ', FIRST_COLUMN_WIDTH);
{ methodDesc.pad_right(' ', SECOND_COLUMN_WIDTH);
helpStream << "\tRequired flags: "; helpStream << "\t" << methodName.get_c_string() << methodDesc.get_c_string();
for (size_t i = 0; i < methodReqFlags.size(); ++i)
{
helpStream << '<' << methodReqFlags[i]->name.string_view() << "> ";
}
}
helpStream << std::endl;
}
helpStream << "Flags:" << std::endl;
for (const CliOption *flag : flags)
{
const char *req = (flag->isRequired ? "Required" : "Optional");
if (flag->hasMatchCharacter)
{
helpStream << "\t -" << flag->matchCharacter << ", --"
<< flag->matchString.string_view() << "=" <<
flag->name.string_view() << " - " << flag->description.string_view() << " [" << req;
}
else
{
helpStream << "\t --" << flag->matchString.string_view() << "=" <<
flag->name.string_view() << " - " << flag->description.string_view() << " [" << req;
}
auto *intFlag = dynamic_cast<const CliValueFlag<int> *> (flag); auto methodReqFlags = method->get_required_flags();
if (intFlag) auto methodOptionalFlags = method->get_optional_flags();
helpStream << ", int"; if (!methodReqFlags.empty() || !methodOptionalFlags.empty())
auto *uintFlag = dynamic_cast<const CliValueFlag<unsigned int> *> (flag);
if (uintFlag)
{ {
helpStream << ", uint"; helpStream << " Flags: ";
} }
auto *floatFlag = dynamic_cast<const CliValueFlag<float> *> (flag); for (const auto &methodReqFlag : methodReqFlags)
if (floatFlag)
{ {
helpStream << ", float"; helpStream << '<' << methodReqFlag->name.string_view() << "> ";
} }
for (const auto &methodOptionalFlag : methodOptionalFlags)
auto *constCharFlag = dynamic_cast<const CliValueFlag<const char *> *> (flag);
if (constCharFlag)
{ {
helpStream << ", const char*"; helpStream << '[' << methodOptionalFlag->name.string_view() << "] ";
} }
helpStream << std::endl;
}
auto *stringFlag = dynamic_cast<const CliValueFlag<std::string> *> (flag); helpStream << "Flags:" << std::endl;
if (stringFlag) print_flags(helpStream, get_flags_not_in_group());
{ for (const CliOptionGroup &group : groups)
helpStream << ", std::string"; {
} helpStream << "Flags - " << group.name.string_view() << std::endl;
helpStream << "]" << std::endl; print_flags(helpStream, group.options);
} }
fprintf(stdout, "%s", helpStream.str().c_str()); fprintf(stdout, "%s", helpStream.str().c_str());
...@@ -308,5 +356,15 @@ namespace azgra ...@@ -308,5 +356,15 @@ namespace azgra
{ {
return someMethodMatched; return someMethodMatched;
} }
void CliArguments::add_group(const CliOptionGroup &flagGroup)
{
groups.push_back(flagGroup);
for (CliOption *flag : flagGroup.options)
{
flag->isInGroup = true;
flags.push_back(flag);
}
}
}; };
}; };
\ No newline at end of file
...@@ -25,7 +25,7 @@ namespace azgra ...@@ -25,7 +25,7 @@ namespace azgra
void SimpleString::free_string(char *memory) void SimpleString::free_string(char *memory)
{ {
if (memory != nullptr) if (memory != nullptr && memory[0] != '\0')
{ {
::operator delete(memory); ::operator delete(memory);
memory = nullptr; memory = nullptr;
...@@ -47,6 +47,7 @@ namespace azgra ...@@ -47,6 +47,7 @@ namespace azgra
{ {
size_t inputStringLen = c_string_length(string); size_t inputStringLen = c_string_length(string);
_isEmpty = (inputStringLen == 0);
_length = inputStringLen; _length = inputStringLen;
_string = alloc_string(_length + 1); _string = alloc_string(_length + 1);
...@@ -56,11 +57,51 @@ namespace azgra ...@@ -56,11 +57,51 @@ namespace azgra
_string[_length] = '\0'; _string[_length] = '\0';
} }
SimpleString::SimpleString(const char *cString)
{
internal_initalize(cString);
}
SimpleString::SimpleString(char *cString, const size_t length, bool noAlloc) SimpleString::SimpleString(char *cString, const size_t length, bool noAlloc)
{ {
assert(noAlloc); assert(noAlloc);
_string = cString; _string = cString;
_length = length; _length = length;
_isEmpty = (length == 0);
}
SimpleString::SimpleString(const std::vector<const char *> &strings)
{
_isEmpty = true;
size_t finalLen = 0;
std::vector<size_t> lengths;
for (const char *string : strings)
{
size_t len = c_string_length(string);
lengths.push_back(len);
finalLen += len;
}
if (finalLen > 0)
{
_isEmpty = false;
_string = alloc_string(finalLen + 1);
size_t offset = 0;
for (size_t stringIndex = 0; stringIndex < strings.size(); ++stringIndex)
{
memcpy(_string + offset, strings[stringIndex], lengths[stringIndex] );
offset += lengths[stringIndex];
}
_string[finalLen] = '\0';
_length = finalLen;
}
}
SimpleString::SimpleString()
{
_string = nullptr;
_length = 0;
_isEmpty = true;
} }
SimpleString::operator const char *() const SimpleString::operator const char *() const
...@@ -84,6 +125,12 @@ namespace azgra ...@@ -84,6 +125,12 @@ namespace azgra
concat(cString); concat(cString);
} }
void SimpleString::operator+=(const char c)
{
char stringToAdd[1] = {c};
this->operator+=(stringToAdd);
}
SimpleString SimpleString::operator+(const char *cString) const SimpleString SimpleString::operator+(const char *cString) const
{ {
SimpleString result(_string); SimpleString result(_string);
...@@ -91,6 +138,14 @@ namespace azgra ...@@ -91,6 +138,14 @@ namespace azgra
return result; return result;
} }
SimpleString SimpleString::operator+(const char c) const
{
SimpleString result(_string);
char stringToAdd[1] = {c};
result.concat(stringToAdd);
return result;
}
bool SimpleString::operator==(const char *cString) const bool SimpleString::operator==(const char *cString) const
{ {
return equals(cString); return equals(cString);
...@@ -101,11 +156,6 @@ namespace azgra ...@@ -101,11 +156,6 @@ namespace azgra
return equals(string); return equals(string);
} }
SimpleString::SimpleString(const char *cString)
{
internal_initalize(cString);
}
SimpleString::~SimpleString() SimpleString::~SimpleString()
{ {
free_string(_string); free_string(_string);
...@@ -540,40 +590,48 @@ namespace azgra ...@@ -540,40 +590,48 @@ namespace azgra
return result; return result;
} }
void SimpleString::pad_left(const char padChar, const size_t padCount) void SimpleString::pad_left(const char padChar, const size_t desiredWidth)
{ {
size_t resultLen = _length + padCount; assert(_length <= desiredWidth);
char *result = alloc_string(resultLen); if (_length == desiredWidth)
return;
for (int i = 0; i < padCount; ++i) char *result = alloc_string(desiredWidth + 1);
int fillSize = desiredWidth - _length;
for (int i = 0; i < fillSize; ++i)
{ {
result[i] = padChar; result[i] = padChar;
} }
for (int j = 0; j < _length; ++j) for (int j = 0; j < _length; ++j)
{ {
result[padCount + j] = _string[j]; result[fillSize + j] = _string[j];
} }
result[desiredWidth] = '\0';
free_string(_string); free_string(_string);
_string = result; _string = result;
_length = resultLen; _length = desiredWidth;
} }
void SimpleString::pad_right(const char padChar, const size_t padCount) void SimpleString::pad_right(const char padChar, const size_t desiredWidth)
{ {
size_t resultLen = _length + padCount; assert(_length <= desiredWidth);
_string = realloc_string(resultLen + 1, _string, _length); if (_length == desiredWidth)
for (int i = 0; i < padCount; ++i) return;
_string = realloc_string(desiredWidth + 1, _string, _length);
int fillSize = desiredWidth - _length;
for (int i = 0; i < fillSize; ++i)
{ {
_string[_length + i] = padChar; _string[_length + i] = padChar;
} }
_length = resultLen; _length = desiredWidth;
_string[resultLen] = '\0'; _string[desiredWidth] = '\0';
} }
void SimpleString::centerize(const char padChar, const size_t outputWidth) void SimpleString::centerize(const char padChar, const size_t outputWidth)
{ {
size_t actualOutputWidth = (_length < outputWidth) ? outputWidth : (_length + 4); size_t actualOutputWidth = (_length < outputWidth) ? outputWidth : (_length + 4);
size_t halfPadSize = (actualOutputWidth - 2 - static_cast<int>(_length)) / 2; size_t halfPadSize = (actualOutputWidth - 2 - static_cast<int>(_length)) / 2;
char *result = alloc_string(actualOutputWidth + 1); char *result = alloc_string(actualOutputWidth + 1);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment