Browse Source

Replaced findi usage with jessilib; removed some other methods; way more code adjustment than anticipated

task/remove_strings
Jessica James 3 years ago
parent
commit
90165eead3
  1. 16
      src/common/Command.cpp
  2. 73
      src/common/Config.cpp
  3. 3
      src/common/GenericCommand.cpp
  4. 48
      src/common/INIConfig.cpp
  5. 120
      src/common/IRC_Client.cpp
  6. 10
      src/common/SecureSocket.cpp
  7. 6
      src/include/Jupiter/Command.h
  8. 42
      src/include/Jupiter/Config.h
  9. 4
      src/include/Jupiter/DataBuffer_Imp.h
  10. 15
      src/include/Jupiter/HTTP_QueryString.h
  11. 24
      src/include/Jupiter/IRC_Client.h
  12. 59
      src/include/Jupiter/Readable_String.h
  13. 238
      src/include/Jupiter/Readable_String_Imp.h
  14. 4
      src/include/Jupiter/SecureSocket.h
  15. 15
      src/include/Jupiter/String.hpp
  16. 2
      src/include/Jupiter/String_Type.h
  17. 16
      src/include/Jupiter/String_Type_Imp.h
  18. 2
      src/jessilib

16
src/common/Command.cpp

@ -17,11 +17,12 @@
*/ */
#include <cstring> #include <cstring>
#include "jessilib/unicode.hpp"
#include "Command.h" #include "Command.h"
#include "String.hpp" #include "String.hpp"
struct Jupiter::Command::Data { // TODO: remove pimpl struct Jupiter::Command::Data { // TODO: remove pimpl
std::vector<Jupiter::StringS> triggers; std::vector<std::string> triggers;
}; };
Jupiter::Command::Command() { Jupiter::Command::Command() {
@ -40,11 +41,11 @@ Jupiter::Command::~Command() {
// Command Functions // Command Functions
void Jupiter::Command::addTrigger(const Jupiter::ReadableString &trigger) { void Jupiter::Command::addTrigger(std::string_view trigger) {
m_data->triggers.emplace_back(trigger); m_data->triggers.emplace_back(trigger);
} }
const Jupiter::ReadableString &Jupiter::Command::getTrigger(size_t index) const { std::string_view Jupiter::Command::getTrigger(size_t index) const {
return m_data->triggers[index]; return m_data->triggers[index];
} }
@ -52,8 +53,11 @@ size_t Jupiter::Command::getTriggerCount() const {
return m_data->triggers.size(); return m_data->triggers.size();
} }
bool Jupiter::Command::matches(const Jupiter::ReadableString &in_trigger) const { bool Jupiter::Command::matches(std::string_view in_trigger) const {
for (const auto& trigger : m_data->triggers) for (const auto& trigger : m_data->triggers) {
if (trigger.equalsi(in_trigger)) return true; if (jessilib::equalsi(trigger, in_trigger)) {
return true;
}
}
return false; return false;
} }

73
src/common/Config.cpp

@ -29,9 +29,9 @@ Jupiter::Config& Jupiter::Config::operator=(const Config& in_config) {
return *this; return *this;
} }
const Jupiter::ReadableString &Jupiter::Config::get(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_default_value) const std::string_view Jupiter::Config::get(std::string_view in_key, std::string_view in_default_value) const
{ {
auto value = m_table.find(in_key); auto value = m_table.find(JUPITER_WRAP_CONFIG_KEY(in_key));
if (value != m_table.end()) { if (value != m_table.end()) {
return value->second; return value->second;
} }
@ -39,10 +39,10 @@ const Jupiter::ReadableString &Jupiter::Config::get(const Jupiter::ReadableStrin
return in_default_value; return in_default_value;
} }
Jupiter::Config *Jupiter::Config::getSection(const Jupiter::ReadableString &in_key) const Jupiter::Config *Jupiter::Config::getSection(std::string_view in_key) const
{ {
if (m_sections != nullptr) { if (m_sections != nullptr) {
auto section = m_sections->find(in_key); auto section = m_sections->find(JUPITER_WRAP_CONFIG_KEY(in_key));
if (section != m_sections->end()) { if (section != m_sections->end()) {
return &section->second; return &section->second;
} }
@ -51,56 +51,69 @@ Jupiter::Config *Jupiter::Config::getSection(const Jupiter::ReadableString &in_k
return nullptr; return nullptr;
} }
Jupiter::Config &Jupiter::Config::getSectionReference(const Jupiter::ReadableString &in_key) Jupiter::Config &Jupiter::Config::getSectionReference(std::string_view in_key)
{ {
if (m_sections == nullptr) { if (m_sections == nullptr) {
m_sections = std::make_unique<SectionHashTable>(); m_sections = std::make_unique<SectionHashTable>();
} }
Config& section = (*m_sections)[in_key]; auto section = m_sections->find(JUPITER_WRAP_CONFIG_KEY(in_key));
if (section == m_sections->end()) {
// for some reason msvc doesn't like emplace
section = m_sections->try_emplace(static_cast<std::string>(in_key)).first;
}
if (section.m_name.empty()) { if (section->second.m_name.empty()) {
section.m_name = static_cast<std::string>(in_key); section->second.m_name = in_key;
} }
return section; return section->second;
} }
bool Jupiter::Config::set(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_value) bool Jupiter::Config::set(std::string_view in_key, std::string in_value) {
{ return m_table.insert_or_assign(static_cast<std::string>(in_key), std::move(in_value)).second;
return m_table.insert_or_assign(in_key, in_value).second;
} }
bool Jupiter::Config::remove(const Jupiter::ReadableString &in_key) bool Jupiter::Config::remove(std::string_view in_key) {
{ auto value = m_table.find(JUPITER_WRAP_CONFIG_KEY(in_key));
return m_table.erase(in_key) > 0; if (value == m_table.end()) {
return false;
}
m_table.erase(value);
return true;
} }
bool Jupiter::Config::removeSection(const Jupiter::ReadableString &in_key) bool Jupiter::Config::removeSection(std::string_view in_key) {
{ if (m_sections == nullptr) {
return m_sections != nullptr && m_sections->erase(in_key) > 0; return false;
}
auto section = m_sections->find(JUPITER_WRAP_CONFIG_KEY(in_key));
if (section == m_sections->end()) {
return false;
}
m_sections->erase(section);
return true;
} }
const std::string &Jupiter::Config::getName() const const std::string &Jupiter::Config::getName() const {
{
return m_name; return m_name;
} }
void Jupiter::Config::erase() void Jupiter::Config::erase() {
{
m_table.clear(); m_table.clear();
m_sections = nullptr; m_sections = nullptr;
} }
bool Jupiter::Config::read(const char *in_filename) bool Jupiter::Config::read(const char *in_filename) {
{
m_name = in_filename; m_name = in_filename;
return this->read_internal(in_filename); return this->read_internal(in_filename);
} }
bool Jupiter::Config::read(const std::string_view& in_filename) bool Jupiter::Config::read(std::string_view in_filename) {
{ m_name = in_filename;
m_name = static_cast<std::string>(in_filename);
return this->read_internal(m_name.c_str()); return this->read_internal(m_name.c_str());
} }
@ -114,7 +127,7 @@ bool Jupiter::Config::write(const char *in_filename)
return this->write_internal(in_filename); return this->write_internal(in_filename);
} }
bool Jupiter::Config::write(const Jupiter::ReadableString &in_filename) bool Jupiter::Config::write(std::string_view in_filename)
{ {
return this->write(static_cast<std::string>(in_filename).c_str()); return this->write(static_cast<std::string>(in_filename).c_str());
} }
@ -131,7 +144,7 @@ bool Jupiter::Config::reload(const char *in_filename)
return this->read(in_filename); return this->read(in_filename);
} }
bool Jupiter::Config::reload(const Jupiter::ReadableString &in_filename) bool Jupiter::Config::reload(std::string_view in_filename)
{ {
this->erase(); this->erase();
return this->read(in_filename); return this->read(in_filename);
@ -146,7 +159,7 @@ const Jupiter::Config::SectionHashTable &Jupiter::Config::getSections() const {
} }
/** Operators */ /** Operators */
Jupiter::Config &Jupiter::Config::operator[](const Jupiter::ReadableString &in_key) Jupiter::Config &Jupiter::Config::operator[](std::string_view in_key)
{ {
return this->getSectionReference(in_key); return this->getSectionReference(in_key);
} }

3
src/common/GenericCommand.cpp

@ -227,7 +227,8 @@ void Jupiter::GenericCommandNamespace::updateHelp() {
m_should_update_help = false; m_should_update_help = false;
std::vector<Jupiter::GenericCommand*> commands = getCommands(); std::vector<Jupiter::GenericCommand*> commands = getCommands();
Jupiter::StringL tmp_help(commands.size() * 8); std::string tmp_help;
tmp_help.reserve(commands.size() * 8);
for (const auto& command : commands) { for (const auto& command : commands) {
tmp_help += command->getTrigger(); tmp_help += command->getTrigger();

48
src/common/INIConfig.cpp

@ -53,9 +53,10 @@ void Jupiter::INIConfig::write_helper(FILE *in_file, const Jupiter::Config *in_s
fputc('\t', in_file); fputc('\t', in_file);
// Write entry // Write entry
table_entry.first.print(in_file); fwrite(table_entry.first.data(), sizeof(char), table_entry.first.size(), in_file);
fputs(" = ", in_file); fputs(" = ", in_file);
table_entry.second.println(in_file); fwrite(table_entry.second.data(), sizeof(char), table_entry.second.size(), in_file);
fputs("\r\n", in_file);
} }
// Write subsections // Write subsections
@ -80,16 +81,15 @@ bool Jupiter::INIConfig::write_internal(const char *in_filename)
return true; return true;
} }
bool Jupiter::INIConfig::read_internal(const char *in_filename) bool Jupiter::INIConfig::read_internal(const char *in_filename) {
{ std::string_view line;
Jupiter::ReferenceString line;
std::stack<Jupiter::Config *> section_stack; std::stack<Jupiter::Config *> section_stack;
section_stack.push(this); section_stack.push(this);
auto process_line = [&line, &section_stack]() auto process_line = [&line, &section_stack]()
{ {
const char *itr = line.ptr(); const char *itr = line.data();
const char *end = itr + line.size(); // guaranteed to be greater than itr const char *end = itr + line.size(); // guaranteed to be greater than itr
// Shift to right of spaces // Shift to right of spaces
@ -98,7 +98,7 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
if (++itr == end) if (++itr == end)
return; // Line is purely whitespace return; // Line is purely whitespace
line.shiftRight(itr - line.ptr()); line.remove_prefix(itr - line.data());
if (*itr == ';') if (*itr == ';')
return; // Comment return; // Comment
@ -112,7 +112,7 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
for (++itr; itr != end && *itr == '['; ++itr) for (++itr; itr != end && *itr == '['; ++itr)
++depth; ++depth;
line.shiftRight(itr - line.ptr()); line.remove_prefix(itr - line.data());
while (end != itr) while (end != itr)
{ {
@ -124,7 +124,7 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
} }
} }
line.set(itr, end - itr); line = std::string_view(itr, end - itr);
// Add section to stack; pop sections or push blanks as necessary // Add section to stack; pop sections or push blanks as necessary
@ -132,9 +132,9 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
section_stack.pop(); section_stack.pop();
while (depth > section_stack.size()) while (depth > section_stack.size())
section_stack.push(std::addressof(section_stack.top()->getSectionReference(Jupiter::ReferenceString::empty))); section_stack.push(std::addressof(section_stack.top()->getSectionReference({})));
section_stack.push(&section_stack.top()->getSectionReference(line)); section_stack.push(&section_stack.top()->getSectionReference(static_cast<KeyType>(line)));
} }
else else
{ {
@ -146,7 +146,7 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
// end now points to a non-space character within the bounds // end now points to a non-space character within the bounds
++end; ++end;
line.truncate(itr + line.size() - end); line.remove_suffix(itr + line.size() - end);
// Parse key (can be empty) // Parse key (can be empty)
@ -154,9 +154,9 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
if (++itr == end) if (++itr == end)
return; // Error: no assignment exists; ignore line return; // Error: no assignment exists; ignore line
Jupiter::ReferenceString key; std::string_view key;
if (itr != line.ptr()) if (itr != line.data())
{ {
// Truncate spaces from key; a non-space character is guaranteed // Truncate spaces from key; a non-space character is guaranteed
end = itr - 1; end = itr - 1;
@ -164,9 +164,9 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
while (isspace(*end)) while (isspace(*end))
--end; --end;
key = line.substring(size_t{ 0 }, end + 1 - line.ptr()); key = line.substr(size_t{ 0 }, end + 1 - line.data());
end = line.ptr() + line.size(); end = line.data() + line.size();
} }
// Parse value (can be empty) // Parse value (can be empty)
@ -177,13 +177,13 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
while (isspace(*itr)) while (isspace(*itr))
++itr; ++itr;
line.shiftRight(itr - line.ptr()); line.remove_prefix(itr - line.data());
} }
else else
line = Jupiter::ReferenceString::empty; line = std::string_view{};
// Add entry to current table on stack // Add entry to current table on stack
section_stack.top()->set(key, line); section_stack.top()->set(KeyType{key}, static_cast<std::string>(line));
} }
}; };
@ -214,7 +214,7 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
end = itr + buffer.size(); end = itr + buffer.size();
// Reset line // Reset line
line.set(buffer.ptr(), 0); line = std::string_view(buffer.ptr(), 0);
// Parse buffer for lines // Parse buffer for lines
while (itr != end) while (itr != end)
@ -223,8 +223,8 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
if (*itr == '\n' || *itr == '\r') if (*itr == '\n' || *itr == '\r')
{ {
// Process line // Process line
line.set(buffer.ptr(), itr - buffer.ptr()); line = std::string_view(buffer.ptr(), itr - buffer.ptr());
if (line.isNotEmpty()) if (!line.empty())
process_line(); process_line();
// Keep iterating until next non-newline character // Keep iterating until next non-newline character
@ -253,8 +253,8 @@ bool Jupiter::INIConfig::read_internal(const char *in_filename)
} }
// Process data remaining in buffer as a line // Process data remaining in buffer as a line
line.set(buffer.ptr(), buffer.size()); line = std::string_view(buffer.ptr(), buffer.size());
if (line.isNotEmpty()) if (!line.empty())
process_line(); process_line();
// File has been successfully read, or an error occurred. // File has been successfully read, or an error occurred.

120
src/common/IRC_Client.cpp

@ -20,6 +20,7 @@
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include "jessilib/split.hpp" #include "jessilib/split.hpp"
#include "jessilib/unicode.hpp"
#include "Jupiter.h" #include "Jupiter.h"
#include "Functions.h" #include "Functions.h"
#include "IRC_Client.h" #include "IRC_Client.h"
@ -38,6 +39,7 @@
#endif // _WIN32 #endif // _WIN32
using namespace Jupiter::literals; using namespace Jupiter::literals;
using namespace std::literals;
Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Config *in_secondary_section) Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Config *in_secondary_section)
{ {
@ -55,11 +57,11 @@ Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Confi
m_realname = Jupiter::IRC::Client::readConfigValue("RealName"_jrs, "Jupiter IRC Client"_jrs); m_realname = Jupiter::IRC::Client::readConfigValue("RealName"_jrs, "Jupiter IRC Client"_jrs);
m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Password"_jrs); m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Password"_jrs);
if (m_sasl_password.isEmpty()) if (m_sasl_password.empty())
m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Pass"_jrs); m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Pass"_jrs);
m_sasl_account = Jupiter::IRC::Client::readConfigValue("SASL.Account"_jrs); m_sasl_account = Jupiter::IRC::Client::readConfigValue("SASL.Account"_jrs);
if (m_sasl_account.isEmpty()) if (m_sasl_account.empty())
m_sasl_account = m_nickname; m_sasl_account = m_nickname;
m_auto_part_message = Jupiter::IRC::Client::readConfigValue("AutoPartMessage"_jrs); m_auto_part_message = Jupiter::IRC::Client::readConfigValue("AutoPartMessage"_jrs);
@ -67,13 +69,13 @@ Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Confi
m_ssl = Jupiter::IRC::Client::readConfigBool("SSL"_jrs); m_ssl = Jupiter::IRC::Client::readConfigBool("SSL"_jrs);
m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Certificate"_jrs); m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Certificate"_jrs);
m_ssl_key = Jupiter::IRC::Client::readConfigValue("Key"_jrs); m_ssl_key = Jupiter::IRC::Client::readConfigValue("Key"_jrs);
if (m_ssl_certificate.isEmpty()) if (m_ssl_certificate.empty())
{ {
m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Cert"_jrs); m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Cert"_jrs);
if (m_ssl_certificate.isEmpty()) if (m_ssl_certificate.empty())
m_ssl_certificate = m_ssl_key; m_ssl_certificate = m_ssl_key;
} }
if (m_ssl_key.isEmpty()) if (m_ssl_key.empty())
m_ssl_key = m_ssl_certificate; m_ssl_key = m_ssl_certificate;
m_join_on_kick = Jupiter::IRC::Client::readConfigBool("AutoJoinOnKick"_jrs); m_join_on_kick = Jupiter::IRC::Client::readConfigBool("AutoJoinOnKick"_jrs);
@ -93,7 +95,7 @@ Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Confi
if (m_ssl) { if (m_ssl) {
Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(); Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket();
if (m_ssl_certificate.isNotEmpty()) if (!m_ssl_certificate.empty())
t->setCertificate(m_ssl_certificate, m_ssl_key); t->setCertificate(m_ssl_certificate, m_ssl_key);
m_socket.reset(t); m_socket.reset(t);
@ -253,12 +255,12 @@ const Jupiter::ReadableString &Jupiter::IRC::Client::getPrefixModes() const
return m_prefix_modes; return m_prefix_modes;
} }
const Jupiter::ReadableString &Jupiter::IRC::Client::getNickname() const std::string_view Jupiter::IRC::Client::getNickname() const
{ {
return m_nickname; return m_nickname;
} }
const Jupiter::ReadableString &Jupiter::IRC::Client::getRealname() const std::string_view Jupiter::IRC::Client::getRealname() const
{ {
return m_realname; return m_realname;
} }
@ -396,9 +398,9 @@ void Jupiter::IRC::Client::setAutoReconnect(int val)
m_max_reconnect_attempts = val; m_max_reconnect_attempts = val;
} }
void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &in_channel) void Jupiter::IRC::Client::joinChannel(std::string_view in_channel)
{ {
m_socket->send(Jupiter::StringS::Format("JOIN %.*s" ENDL, in_channel.size(), in_channel.ptr())); m_socket->send(Jupiter::StringS::Format("JOIN %.*s" ENDL, in_channel.size(), in_channel.data()));
} }
void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_password) void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_password)
@ -413,9 +415,9 @@ void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &in_channel
m_channels[in_channel].setType(-2); m_channels[in_channel].setType(-2);
} }
void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_message) void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &in_channel, std::string_view in_message)
{ {
m_socket->send(Jupiter::StringS::Format("PART %.*s :%.*s" ENDL, in_channel.size(), in_channel.ptr(), in_message.size(), in_message.ptr())); m_socket->send(Jupiter::StringS::Format("PART %.*s :%.*s" ENDL, in_channel.size(), in_channel.ptr(), in_message.size(), in_message.data()));
m_channels[in_channel].setType(-2); m_channels[in_channel].setType(-2);
} }
@ -558,7 +560,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
m_socket.reset(t); m_socket.reset(t);
m_ssl = true; m_ssl = true;
// toggle blocking to prevent error // toggle blocking to prevent error
if (m_ssl_certificate.isNotEmpty()) if (!m_ssl_certificate.empty())
t->setCertificate(m_ssl_certificate, m_ssl_key); t->setCertificate(m_ssl_certificate, m_ssl_key);
bool goodSSL; bool goodSSL;
@ -596,7 +598,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
if (w2.equalsi("CAP")) if (w2.equalsi("CAP"))
{ {
Jupiter::ReferenceString w4 = Jupiter::ReferenceString::getWord(line, 3, WHITESPACE); Jupiter::ReferenceString w4 = Jupiter::ReferenceString::getWord(line, 3, WHITESPACE);
if (w4.equals("LS")) if (w4 == "LS"sv)
{ {
Jupiter::ReferenceString listParams = Jupiter::ReferenceString::gotoWord(line, 4, WHITESPACE); Jupiter::ReferenceString listParams = Jupiter::ReferenceString::gotoWord(line, 4, WHITESPACE);
if (listParams[0] == ':') listParams.shiftRight(1); if (listParams[0] == ':') listParams.shiftRight(1);
@ -611,7 +613,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
else if (curr.equalsi("userhost-in-names")) req += "userhost-in-names "; else if (curr.equalsi("userhost-in-names")) req += "userhost-in-names ";
else if (curr.equalsi("sasl")) else if (curr.equalsi("sasl"))
{ {
if (m_sasl_password.isNotEmpty()) if (!m_sasl_password.empty())
{ {
req += "sasl "_jrs; req += "sasl "_jrs;
sasl = true; sasl = true;
@ -667,19 +669,19 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
case Error::NICKNAMEINUSE: // 433 case Error::NICKNAMEINUSE: // 433
case Error::NICKCOLLISION: // 436 case Error::NICKCOLLISION: // 436
case Error::BANNICKCHANGE: // 437 -- Note: This conflicts with another token. case Error::BANNICKCHANGE: // 437 -- Note: This conflicts with another token.
const Jupiter::ReadableString &altNick = Jupiter::IRC::Client::readConfigValue("AltNick"_jrs); std::string_view altNick = Jupiter::IRC::Client::readConfigValue("AltNick"_jrs);
const Jupiter::ReadableString &configNick = Jupiter::IRC::Client::readConfigValue("Nick"_jrs, "Jupiter"_jrs); std::string_view configNick = Jupiter::IRC::Client::readConfigValue("Nick"_jrs, "Jupiter"_jrs);
if (altNick.isNotEmpty() && m_nickname.equalsi(altNick)) // The alternate nick failed. if (!altNick.empty() && jessilib::equalsi(m_nickname, altNick)) // The alternate nick failed.
{ {
m_nickname = configNick; m_nickname = configNick;
m_nickname += "1"; m_nickname += "1";
m_socket->send("NICK "_jrs + m_nickname + ENDL); m_socket->send("NICK "_jrs + m_nickname + ENDL);
} }
else if (m_nickname.equalsi(configNick)) // The config nick failed else if (jessilib::equalsi(m_nickname, configNick)) // The config nick failed
{ {
if (altNick.isEmpty()) if (altNick.empty())
{ {
if (erroneous_nickname) if (erroneous_nickname)
break; // If this nick is invalid, adding numbers won't help. break; // If this nick is invalid, adding numbers won't help.
@ -698,8 +700,9 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
{ {
if (m_nickname.size() > configNick.size()) if (m_nickname.size() > configNick.size())
{ {
int n = Jupiter_strtoi_nospace_s(m_nickname.ptr() + configNick.size(), m_nickname.size() - configNick.size(), 10); int n = Jupiter_strtoi_nospace_s(m_nickname.data() + configNick.size(), m_nickname.size() - configNick.size(), 10);
m_nickname.format("%.*s%d", configNick.size(), configNick.ptr(), n + 1); m_nickname = configNick;
m_nickname += std::to_string(n + 1);
m_socket->send("NICK "_jrs + m_nickname + ENDL); m_socket->send("NICK "_jrs + m_nickname + ENDL);
} }
@ -832,7 +835,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
Jupiter::ReferenceString message = rawmessage.substring(rawmessage.find(' ') + 1, rawmessage.find(IRC::CTCP)); Jupiter::ReferenceString message = rawmessage.substring(rawmessage.find(' ') + 1, rawmessage.find(IRC::CTCP));
if (message[message.size() - 1] == IRC::CTCP) message.truncate(1); if (message[message.size() - 1] == IRC::CTCP) message.truncate(1);
if (command.equals("ACTION")) if (command == "ACTION"sv)
{ {
this->OnAction(chan, nick, message); this->OnAction(chan, nick, message);
for (auto& plugin : Jupiter::plugins) { for (auto& plugin : Jupiter::plugins) {
@ -846,14 +849,14 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
response += " :" IRCCTCP; response += " :" IRCCTCP;
response += command; response += command;
response += ' '; response += ' ';
if (command.equals("PING")) response += message; if (command == "PING"sv) response += message;
else if (command.equals("VERSION")) response += Jupiter::version; else if (command == "VERSION"sv) response += Jupiter::version;
else if (command.equals("FINGER")) response += "Oh, yeah, a little to the left."; else if (command == "FINGER"sv) response += "Oh, yeah, a little to the left.";
else if (command.equals("SOURCE")) response += "https://github.com/JAJames/Jupiter"; else if (command == "SOURCE"sv) response += "https://github.com/JAJames/Jupiter";
else if (command.equals("USERINFO")) response += "Hey, I'm Jupiter! If you have questions, ask Agent! (GitHub: JAJames; Discord: Agent#0001)"; else if (command == "USERINFO"sv) response += "Hey, I'm Jupiter! If you have questions, ask Agent! (GitHub: JAJames; Discord: Agent#0001)";
else if (command.equals("CLIENTINFO")) response += "I'll tell you what I don't know: This command!"; else if (command == "CLIENTINFO"sv) response += "I'll tell you what I don't know: This command!";
else if (command.equals("TIME")) response += getTime(); else if (command == "TIME"sv) response += getTime();
else if (command.equals("ERRMSG")) response += message; else if (command == "ERRMSG"sv) response += message;
else else
{ {
response = "NOTICE "; response = "NOTICE ";
@ -938,7 +941,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
auto channel = getChannel(chan); auto channel = getChannel(chan);
if (m_nickname.equalsi(nick)) if (jessilib::equalsi(m_nickname, nick))
{ {
// TODO: Optimize by simply wiping channel data, rather than removing and re-adding // TODO: Optimize by simply wiping channel data, rather than removing and re-adding
if (channel != nullptr) if (channel != nullptr)
@ -950,7 +953,7 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
if (channel->getType() < 0) if (channel->getType() < 0)
{ {
if (m_auto_part_message.isNotEmpty()) if (!m_auto_part_message.empty())
Jupiter::IRC::Client::partChannel(chan, m_auto_part_message); Jupiter::IRC::Client::partChannel(chan, m_auto_part_message);
else else
Jupiter::IRC::Client::partChannel(chan); Jupiter::IRC::Client::partChannel(chan);
@ -1179,16 +1182,16 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
} }
else else
{ {
if (w1.equals("PING")) if (w1 == "PING"sv)
{ {
m_socket->send(Jupiter::StringS::Format("PONG %.*s" ENDL, w2.size(), w2.ptr())); m_socket->send(Jupiter::StringS::Format("PONG %.*s" ENDL, w2.size(), w2.ptr()));
} }
else if (w1.equals("NICK")) else if (w1 == "NICK"sv)
{ {
if (w2.isNotEmpty()) if (w2.isNotEmpty())
m_nickname = w2; m_nickname = w2;
} }
else if (w1.equals("ERROR")) else if (w1 == "ERROR"sv)
{ {
Jupiter::ReferenceString reason = Jupiter::ReferenceString::substring(line, line.find(':') + 1); Jupiter::ReferenceString reason = Jupiter::ReferenceString::substring(line, line.find(':') + 1);
this->OnError(reason); this->OnError(reason);
@ -1197,9 +1200,9 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
} }
Jupiter::IRC::Client::disconnect(); Jupiter::IRC::Client::disconnect();
} }
else if (w1.equals("AUTHENTICATE")) else if (w1 == "AUTHENTICATE"sv)
{ {
if (m_sasl_password.isNotEmpty()) if (!m_sasl_password.empty())
{ {
Jupiter::StringS auth_str = m_nickname + '\0' + m_sasl_account + '\0' + m_sasl_password; Jupiter::StringS auth_str = m_nickname + '\0' + m_sasl_account + '\0' + m_sasl_password;
@ -1230,8 +1233,8 @@ int Jupiter::IRC::Client::process_line(std::string_view in_line) {
bool Jupiter::IRC::Client::connect() bool Jupiter::IRC::Client::connect()
{ {
const Jupiter::ReadableString &clientAddress = Jupiter::IRC::Client::readConfigValue("ClientAddress"_jrs); std::string_view clientAddress = Jupiter::IRC::Client::readConfigValue("ClientAddress"_jrs);
if (m_socket->connect(m_server_hostname.c_str(), m_server_port, clientAddress.isEmpty() ? nullptr : static_cast<std::string>(clientAddress).c_str(), (unsigned short)Jupiter::IRC::Client::readConfigLong("ClientPort"_jrs)) == false) if (m_socket->connect(m_server_hostname.c_str(), m_server_port, clientAddress.empty() ? nullptr : static_cast<std::string>(clientAddress).c_str(), (unsigned short)Jupiter::IRC::Client::readConfigLong("ClientPort"_jrs)) == false)
return false; return false;
m_socket->setBlocking(false); m_socket->setBlocking(false);
@ -1260,7 +1263,7 @@ void Jupiter::IRC::Client::disconnect(bool stayDead)
if (m_ssl) if (m_ssl)
{ {
Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(std::move(*m_socket)); Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(std::move(*m_socket));
if (m_ssl_certificate.isNotEmpty()) if (!m_ssl_certificate.empty())
t->setCertificate(m_ssl_certificate, m_ssl_key); t->setCertificate(m_ssl_certificate, m_ssl_key);
m_socket.reset(t); m_socket.reset(t);
@ -1365,13 +1368,12 @@ int Jupiter::IRC::Client::think()
return handle_error(tmp); return handle_error(tmp);
} }
const Jupiter::ReadableString &Jupiter::IRC::Client::readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &defaultValue) const std::string_view Jupiter::IRC::Client::readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &defaultValue) const
{ {
if (m_primary_section != nullptr) if (m_primary_section != nullptr)
{ {
const Jupiter::ReadableString &val = m_primary_section->get(key); std::string_view val = m_primary_section->get(key);
if (!val.empty())
if (val.isNotEmpty())
return val; return val;
} }
@ -1385,10 +1387,10 @@ bool Jupiter::IRC::Client::readConfigBool(const Jupiter::ReadableString &key, bo
{ {
if (m_primary_section != nullptr) if (m_primary_section != nullptr)
{ {
const Jupiter::ReadableString &val = m_primary_section->get(key); std::string_view val = m_primary_section->get(key);
if (val.isNotEmpty()) if (!val.empty())
return val.asBool(); return Jupiter::ReferenceString{val}.asBool();
} }
if (m_secondary_section != nullptr) if (m_secondary_section != nullptr)
@ -1401,10 +1403,10 @@ int Jupiter::IRC::Client::readConfigInt(const Jupiter::ReadableString &key, int
{ {
if (m_primary_section != nullptr) if (m_primary_section != nullptr)
{ {
const Jupiter::ReadableString &val = m_primary_section->get(key); std::string_view val = m_primary_section->get(key);
if (val.isNotEmpty()) if (!val.empty())
return val.asInt(); return Jupiter::ReferenceString{val}.asInt();
} }
if (m_secondary_section != nullptr) if (m_secondary_section != nullptr)
@ -1417,10 +1419,10 @@ long Jupiter::IRC::Client::readConfigLong(const Jupiter::ReadableString &key, lo
{ {
if (m_primary_section != nullptr) if (m_primary_section != nullptr)
{ {
const Jupiter::ReadableString &val = m_primary_section->get(key); std::string_view val = m_primary_section->get(key);
if (val.isNotEmpty()) if (!val.empty())
return val.asInt(); return Jupiter::ReferenceString{val}.asInt();
} }
if (m_secondary_section != nullptr) if (m_secondary_section != nullptr)
@ -1433,10 +1435,10 @@ double Jupiter::IRC::Client::readConfigDouble(const Jupiter::ReadableString &key
{ {
if (m_primary_section != nullptr) if (m_primary_section != nullptr)
{ {
const Jupiter::ReadableString &val = m_primary_section->get(key); std::string_view val = m_primary_section->get(key);
if (val.isNotEmpty()) if (!val.empty())
return val.asDouble(); return Jupiter::ReferenceString{val}.asDouble();
} }
if (m_secondary_section != nullptr) if (m_secondary_section != nullptr)
@ -1530,12 +1532,12 @@ bool Jupiter::IRC::Client::registerClient()
const char *localHostname = Jupiter::Socket::getLocalHostname(); const char *localHostname = Jupiter::Socket::getLocalHostname();
Jupiter::StringS messageToSend; Jupiter::StringS messageToSend;
messageToSend.format("USER %.*s %s %.*s :%.*s" ENDL, m_nickname.size(), m_nickname.ptr(), localHostname, m_server_hostname.size(), m_server_hostname.c_str(), m_realname.size(), m_realname.ptr()); messageToSend.format("USER %.*s %s %.*s :%.*s" ENDL, m_nickname.size(), m_nickname.data(), localHostname, m_server_hostname.size(), m_server_hostname.c_str(), m_realname.size(), m_realname.data());
if (m_socket->send(messageToSend) <= 0) if (m_socket->send(messageToSend) <= 0)
result = false; result = false;
messageToSend.format("NICK %.*s" ENDL, m_nickname.size(), m_nickname.ptr()); messageToSend.format("NICK %.*s" ENDL, m_nickname.size(), m_nickname.data());
if (m_socket->send(messageToSend) <= 0) if (m_socket->send(messageToSend) <= 0)
result = false; result = false;

10
src/common/SecureSocket.cpp

@ -178,15 +178,15 @@ bool loadCertificate(SSL_CTX *context, const char *cert, const char *key)
return true; return true;
} }
void Jupiter::SecureSocket::setCertificate(const Jupiter::ReadableString &cert, const Jupiter::ReadableString &key) void Jupiter::SecureSocket::setCertificate(std::string cert, std::string key)
{ {
Jupiter::SecureSocket::SSLdata_->cert = static_cast<std::string>(cert); Jupiter::SecureSocket::SSLdata_->cert = std::move(cert);
Jupiter::SecureSocket::SSLdata_->key = static_cast<std::string>(key); Jupiter::SecureSocket::SSLdata_->key = std::move(key);
} }
void Jupiter::SecureSocket::setCertificate(const Jupiter::ReadableString &pem) void Jupiter::SecureSocket::setCertificate(std::string_view pem)
{ {
Jupiter::SecureSocket::setCertificate(pem, pem); Jupiter::SecureSocket::setCertificate(static_cast<std::string>(pem), static_cast<std::string>(pem));
} }
bool Jupiter::SecureSocket::connect(const char *hostname, unsigned short iPort, const char *clientAddress, unsigned short clientPort) bool Jupiter::SecureSocket::connect(const char *hostname, unsigned short iPort, const char *clientAddress, unsigned short clientPort)

6
src/include/Jupiter/Command.h

@ -41,7 +41,7 @@ namespace Jupiter
* *
* @param trigger Trigger to add to the command. * @param trigger Trigger to add to the command.
*/ */
void addTrigger(const Jupiter::ReadableString &trigger); void addTrigger(std::string_view trigger);
/** /**
* @brief Fetches a command's specified trigger. * @brief Fetches a command's specified trigger.
@ -49,7 +49,7 @@ namespace Jupiter
* @param index Index of the trigger to return. * @param index Index of the trigger to return.
* @return Trigger of the command at the specified index. * @return Trigger of the command at the specified index.
*/ */
const Jupiter::ReadableString &getTrigger(size_t index = 0) const; std::string_view getTrigger(size_t index = 0) const;
/** /**
* @brief Returns the number of triggers accepted by the command. * @brief Returns the number of triggers accepted by the command.
@ -65,7 +65,7 @@ namespace Jupiter
* @param trigger Trigger to check against the trigger list. * @param trigger Trigger to check against the trigger list.
* @return True if a match was found, false otherwise. * @return True if a match was found, false otherwise.
*/ */
bool matches(const Jupiter::ReadableString &trigger) const; bool matches(std::string_view trigger) const;
/** /**
* @brief Returns a brief explanation and syntax description about a command. * @brief Returns a brief explanation and syntax description about a command.

42
src/include/Jupiter/Config.h

@ -46,8 +46,16 @@ namespace Jupiter
{ {
public: public:
/** Hash_Table type for sections */ /** Hash_Table type for sections */
using SectionHashTable = std::unordered_map<StringS, Config, default_hash_function>; using SectionHashTable = std::unordered_map<std::string, Config, str_hash<char>, std::equal_to<>>;
using ValuesHashTable = std::unordered_map<StringS, StringS, default_hash_function>; using ValuesHashTable = std::unordered_map<std::string, std::string, str_hash<char>, std::equal_to<>>;
#ifdef __cpp_lib_generic_unordered_lookup
using KeyType = std::string_view;
#define JUPITER_WRAP_CONFIG_KEY(in_key) in_key
#else // We can't use std::string_view for InKeyType until GCC 11 & clang 12, and I still want to support GCC 9
using KeyType = std::string;
#define JUPITER_WRAP_CONFIG_KEY(in_key) static_cast<KeyType>(in_key)
#endif // __cpp_lib_generic_unordered_lookup
Config() = default; Config() = default;
Config(const Config& in_config); Config(const Config& in_config);
@ -62,7 +70,7 @@ namespace Jupiter
* @param in_default_value Value to return if no such entry exists * @param in_default_value Value to return if no such entry exists
* @return Value of the entry if it exists, an empty string otherwise. * @return Value of the entry if it exists, an empty string otherwise.
*/ */
const Jupiter::ReadableString &get(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_default_value = Jupiter::ReferenceString::empty) const; std::string_view get(std::string_view in_key, std::string_view in_default_value = std::string_view{}) const;
/** /**
* @brief Fetches the value of an entry and interprets it as another type. * @brief Fetches the value of an entry and interprets it as another type.
@ -73,7 +81,7 @@ namespace Jupiter
* @param in_default_value Value to return if no such entry exists * @param in_default_value Value to return if no such entry exists
* @return Value of the entry if it exists, 0 otherwise. * @return Value of the entry if it exists, 0 otherwise.
*/ */
template<typename T> T get(const Jupiter::ReadableString &in_key, T in_default_value = 0) const; template<typename T> T get(std::string_view in_key, T in_default_value = 0) const;
/** /**
* @brief Fetches a section based on its name * @brief Fetches a section based on its name
@ -81,7 +89,7 @@ namespace Jupiter
* @param in_key Name of the section to fetch * @param in_key Name of the section to fetch
* @return Pointer to a section if it exists, nullptr otherwise * @return Pointer to a section if it exists, nullptr otherwise
*/ */
Config *getSection(const Jupiter::ReadableString &in_key) const; Config *getSection(std::string_view in_key) const;
/** /**
* @brief Fetches a section based on its name * @brief Fetches a section based on its name
@ -90,7 +98,7 @@ namespace Jupiter
* @param in_key Name of the section to fetch * @param in_key Name of the section to fetch
* @return Reference to the section * @return Reference to the section
*/ */
Config &getSectionReference(const Jupiter::ReadableString &in_key); Config &getSectionReference(std::string_view in_key);
/** /**
* @brief Sets an entry's value in the table * @brief Sets an entry's value in the table
@ -99,7 +107,7 @@ namespace Jupiter
* @param in_value Value to write to the entry * @param in_value Value to write to the entry
* @return True if a new entry was added, false if an entry was overwritten * @return True if a new entry was added, false if an entry was overwritten
*/ */
bool set(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_value); bool set(std::string_view in_key, std::string in_value);
/** /**
* @brief Removes an entry from the table * @brief Removes an entry from the table
@ -107,7 +115,7 @@ namespace Jupiter
* @param in_key Key of the entry to remove * @param in_key Key of the entry to remove
* @return True if an entry was removed, false otherwise * @return True if an entry was removed, false otherwise
*/ */
bool remove(const Jupiter::ReadableString &in_key); bool remove(std::string_view in_key);
/** /**
* @brief Removes a section from the table * @brief Removes a section from the table
@ -115,7 +123,7 @@ namespace Jupiter
* @param in_key Key of the section to remove * @param in_key Key of the section to remove
* @return True if an entry was removed, false otherwise * @return True if an entry was removed, false otherwise
*/ */
bool removeSection(const Jupiter::ReadableString &in_key); bool removeSection(std::string_view in_key);
/** /**
* @brief Fetches the name of this config section * @brief Fetches the name of this config section
@ -123,7 +131,7 @@ namespace Jupiter
* *
* @return Name of this section * @return Name of this section
*/ */
const std::string &getName() const; const std::string& getName() const;
/** /**
* @brief Erases all data from this section * @brief Erases all data from this section
@ -144,7 +152,7 @@ namespace Jupiter
* @param in_filename Name of the file to read from * @param in_filename Name of the file to read from
* @return True on success, false otherwise * @return True on success, false otherwise
*/ */
bool read(const std::string_view& in_filename); bool read(std::string_view in_filename);
/** /**
* @brief Writes config data to the last read file * @brief Writes config data to the last read file
@ -167,7 +175,7 @@ namespace Jupiter
* @param in_filename Name of the file to write to * @param in_filename Name of the file to write to
* @return True on success, false otherwise * @return True on success, false otherwise
*/ */
bool write(const Jupiter::ReadableString &in_filename); bool write(std::string_view in_filename);
/** /**
* @brief Empties config data from memory and reads from the last read file * @brief Empties config data from memory and reads from the last read file
@ -190,7 +198,7 @@ namespace Jupiter
* @param in_filename Name of the file to read from * @param in_filename Name of the file to read from
* @return True on success, false otherwise * @return True on success, false otherwise
*/ */
bool reload(const Jupiter::ReadableString &in_filename); bool reload(std::string_view in_filename);
/** /**
* @brief Fetches a reference to this config's entry table * @brief Fetches a reference to this config's entry table
@ -207,7 +215,7 @@ namespace Jupiter
const SectionHashTable &getSections() const; const SectionHashTable &getSections() const;
/** Subscript operator */ /** Subscript operator */
Config &operator[](const Jupiter::ReadableString &in_key); Config &operator[](std::string_view in_key);
/** Used for low-level string operations */ /** Used for low-level string operations */
class Buffer : public Jupiter::StringL class Buffer : public Jupiter::StringL
@ -245,14 +253,14 @@ namespace Jupiter
/** Template function implementations */ /** Template function implementations */
template<typename T> inline T Jupiter::Config::get(const Jupiter::ReadableString &in_key, T in_default_value) const template<typename T> inline T Jupiter::Config::get(std::string_view in_key, T in_default_value) const
{ {
auto result = m_table.find(in_key); auto result = m_table.find(JUPITER_WRAP_CONFIG_KEY(in_key));
if (result == m_table.end()) if (result == m_table.end())
return in_default_value; return in_default_value;
return static_cast<T>(result->second); return static_cast<T>(Jupiter::ReferenceString{result->second});
} }
/** Re-enable warnings */ /** Re-enable warnings */

4
src/include/Jupiter/DataBuffer_Imp.h

@ -311,7 +311,7 @@ template<> struct _Jupiter_DataBuffer_partial_specialization_impl_std_string<std
auto itr = data->begin(); auto itr = data->begin();
auto end = data->end(); auto end = data->end();
while (itr != end) while (itr != end)
buffer->push<std::basic_string<X, Y, Z>::value_type>(*itr++); buffer->push<typename std::basic_string<X, Y, Z>::value_type>(*itr++);
} }
}; };
@ -322,7 +322,7 @@ template<> struct _Jupiter_DataBuffer_partial_specialization_impl_std_string<std
std::basic_string<X, Y, Z> r; std::basic_string<X, Y, Z> r;
r.reserve(size_); r.reserve(size_);
while (size_-- != 0) while (size_-- != 0)
r.push_back(Jupiter::DataBuffer::interpret_data<std::basic_string<X, Y, Z>::value_type>(head)); r.push_back(Jupiter::DataBuffer::interpret_data<typename std::basic_string<X, Y, Z>::value_type>(head));
return r; return r;
} }
}; };

15
src/include/Jupiter/HTTP_QueryString.h

@ -30,21 +30,6 @@
namespace Jupiter namespace Jupiter
{ {
template<typename CharT>
struct str_hash {
using is_transparent = std::true_type;
// C++17 introduces a requirement that these two operators return the same values for same CharT type, but not
// any requirement that std::hash<> be able to accept both key types. This just ties them for convenience
auto operator()(std::basic_string_view<CharT> in_key) const noexcept {
return std::hash<std::basic_string_view<CharT>>()(in_key);
}
auto operator()(const std::basic_string<CharT>& in_key) const noexcept {
return std::hash<std::basic_string<CharT>>()(in_key);
}
};
namespace HTTP namespace HTTP
{ {
/** /**

24
src/include/Jupiter/IRC_Client.h

@ -495,14 +495,14 @@ namespace Jupiter
* *
* @return String containing a nickame. * @return String containing a nickame.
*/ */
const Jupiter::ReadableString &getNickname() const; std::string_view getNickname() const;
/** /**
* @brief Returns the client's real name. * @brief Returns the client's real name.
* *
* @return String containing a name. * @return String containing a name.
*/ */
const Jupiter::ReadableString &getRealname() const; std::string_view getRealname() const;
/** /**
* @brief Returns the server's name * @brief Returns the server's name
@ -627,7 +627,7 @@ namespace Jupiter
* *
* @param channel Channel to join. * @param channel Channel to join.
*/ */
void joinChannel(const Jupiter::ReadableString &in_channel); void joinChannel(std::string_view in_channel);
/** /**
* @brief Sends a join request with a password. * @brief Sends a join request with a password.
@ -650,7 +650,7 @@ namespace Jupiter
* @param channel Channel to part. * @param channel Channel to part.
* @param message Reason for parting. * @param message Reason for parting.
*/ */
void partChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_message); void partChannel(const Jupiter::ReadableString &in_channel, std::string_view in_message);
/** /**
* @brief Gets the access level of a user. * @brief Gets the access level of a user.
@ -732,7 +732,7 @@ namespace Jupiter
* @param in_default_value Optional parameter specifying the default value to return if none is found. * @param in_default_value Optional parameter specifying the default value to return if none is found.
* @return String containing the key value if it exists, in_default_value otherwise. * @return String containing the key value if it exists, in_default_value otherwise.
*/ */
const Jupiter::ReadableString &readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &in_default_value = Jupiter::ReferenceString::empty) const; std::string_view readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &in_default_value = Jupiter::ReferenceString::empty) const;
/** /**
* @brief Returns a key's value as a boolean. * @brief Returns a key's value as a boolean.
@ -833,11 +833,11 @@ namespace Jupiter
std::string m_server_hostname; std::string m_server_hostname;
bool m_ssl; bool m_ssl;
Jupiter::StringS m_ssl_certificate; std::string m_ssl_certificate;
Jupiter::StringS m_ssl_key; std::string m_ssl_key;
Jupiter::StringS m_sasl_account; std::string m_sasl_account;
Jupiter::StringS m_sasl_password; std::string m_sasl_password;
int m_connection_status; int m_connection_status;
Jupiter::StringS m_primary_section_name; Jupiter::StringS m_primary_section_name;
@ -846,8 +846,8 @@ namespace Jupiter
std::string m_log_file_name; std::string m_log_file_name;
std::string m_last_line; std::string m_last_line;
Jupiter::StringS m_server_name; Jupiter::StringS m_server_name;
Jupiter::StringS m_nickname; std::string m_nickname;
Jupiter::StringS m_realname; std::string m_realname;
Jupiter::StringS m_prefix_modes = "ov"; Jupiter::StringS m_prefix_modes = "ov";
Jupiter::StringS m_prefixes = "@+"; Jupiter::StringS m_prefixes = "@+";
@ -861,7 +861,7 @@ namespace Jupiter
ChannelTableType m_channels; ChannelTableType m_channels;
bool m_join_on_kick; bool m_join_on_kick;
Jupiter::StringS m_auto_part_message; std::string m_auto_part_message;
time_t m_reconnect_delay; time_t m_reconnect_delay;
time_t m_reconnect_time; time_t m_reconnect_time;
int m_max_reconnect_attempts; int m_max_reconnect_attempts;

59
src/include/Jupiter/Readable_String.h

@ -72,14 +72,15 @@ namespace Jupiter
* *
* @return True if the String is empty, false otherwise. * @return True if the String is empty, false otherwise.
*/ */
virtual bool isEmpty() const; bool isEmpty() const { return size() == 0; };
bool empty() const { return size() == 0; };
/** /**
* @brief Checks if the String is not empty. * @brief Checks if the String is not empty.
* *
* @return True if the String is not empty, false otherwise. * @return True if the String is not empty, false otherwise.
*/ */
virtual bool isNotEmpty() const; virtual bool isNotEmpty() const { return !empty(); };
/** /**
* @brief Checks if the string contains an element with the specified value. * @brief Checks if the string contains an element with the specified value.
@ -99,17 +100,6 @@ namespace Jupiter
size_t find(const T &value, size_t index = 0) const; size_t find(const T &value, size_t index = 0) const;
size_t find(const Readable_String<T> &in) const; size_t find(const Readable_String<T> &in) const;
/**
* @brief Returns the index of the first element in the string with the specified value.
* Note: Case insensitive. Returns false for any type other than char and wchar_t.
*
* @param value Value of the element to search for.
* @param index Index of the match to return (i.e: 0 returns the first match).
* @return The index of an element if one is found, INVALID_INDEX otherwise.
*/
size_t findi(const T &value, size_t index = 0) const;
size_t findi(const Readable_String<T> &in) const;
/** /**
* @brief Returns the number of elements of the string which match the input string. * @brief Returns the number of elements of the string which match the input string.
* *
@ -120,32 +110,6 @@ namespace Jupiter
size_t span(const T *str) const; size_t span(const T *str) const;
size_t span(const T &in) const; size_t span(const T &in) const;
/**
* @brief Compares another string against the String.
*
* @param in String to compare against.
* @return 0 if the strings are equal, negative if the first mismatched character is greater in the String, or positive if it's less.
*/
int compare(const Readable_String<T> &in) const;
int compare(const std::basic_string<T> &in) const;
int compare(const T *in) const;
int compare(const T &in) const;
int compare(const std::nullptr_t) const;
/**
* @brief Checks if the strings are equal.
* Note: Case sensitive.
*
* @param in String to compare against.
* @return True if the contents of the strings are equal, false otherwise.
*/
bool equals(const Readable_String<T> &in) const;
bool equals(const std::basic_string<T> &in) const;
bool equals(const T *in, size_t len) const;
bool equals(const T *in) const;
bool equals(const T &in) const;
bool equals(const std::nullptr_t) const;
/** /**
* @brief Checks if the strings are equal. * @brief Checks if the strings are equal.
* Note: Case insensitive. Returns false for any type other than char and wchar_t. * Note: Case insensitive. Returns false for any type other than char and wchar_t.
@ -156,9 +120,7 @@ namespace Jupiter
bool equalsi(const Readable_String<T> &in) const; bool equalsi(const Readable_String<T> &in) const;
bool equalsi(const std::basic_string<T> &in) const; bool equalsi(const std::basic_string<T> &in) const;
bool equalsi(const T *in, size_t len) const; bool equalsi(const T *in, size_t len) const;
bool equalsi(const T *in) const;
bool equalsi(const T &in) const; bool equalsi(const T &in) const;
bool equalsi(const std::nullptr_t) const;
/** /**
* @brief Checks if the String matches a wildcard format. * @brief Checks if the String matches a wildcard format.
@ -273,29 +235,26 @@ namespace Jupiter
inline const T &operator[](size_t index) const { return this->get(index); }; inline const T &operator[](size_t index) const { return this->get(index); };
/** Comparative operators */ /** Comparative operators */
inline bool operator==(const Readable_String<T> &right)const{ return this->equals(right); } inline bool operator==(const Readable_String<T>& right)const{ return operator==(std::basic_string_view<T>{right}); }
inline bool operator==(const std::basic_string<T> &right)const{ return this->equals(right); } inline bool operator==(const std::basic_string<T>& right)const{ return operator==(std::basic_string_view<T>{right}); }
inline bool operator==(const T *right)const{ return this->equals(right); } inline bool operator==(const std::basic_string_view<T>& right)const{ return std::basic_string_view<T>(ptr(), size()) == right; }
inline bool operator==(const T right)const{ return this->equals(right); } inline bool operator==(const T right)const{ return this->size() == 1 && this->get(0) == right; }
inline bool operator==(std::nullptr_t) = delete;
inline bool operator!=(const Readable_String<T> &right)const{ return !operator==(right); } inline bool operator!=(const Readable_String<T> &right)const{ return !operator==(right); }
inline bool operator!=(const std::basic_string<T> &right)const{ return !operator==(right); } inline bool operator!=(const std::basic_string<T> &right)const{ return !operator==(right); }
inline bool operator!=(const T *right)const{ return !operator==(right); }
inline bool operator!=(const T right)const{ return !operator==(right); } inline bool operator!=(const T right)const{ return !operator==(right); }
inline bool operator!=(std::nullptr_t) = delete;
inline bool operator<(const Readable_String<T> &right)const{ return this->compare(right) < 0; } inline bool operator<(const Readable_String<T> &right)const{ return this->compare(right) < 0; }
inline bool operator<(const std::basic_string<T> &right)const{ return this->compare(right) < 0; } inline bool operator<(const std::basic_string<T> &right)const{ return this->compare(right) < 0; }
inline bool operator<(const T *right)const{ return this->compare(right) < 0; }
inline bool operator<(const T right)const{ return this->compare(right) < 0; } inline bool operator<(const T right)const{ return this->compare(right) < 0; }
inline bool operator>(const Readable_String<T> &right)const{ return this->compare(right) > 0; } inline bool operator>(const Readable_String<T> &right)const{ return this->compare(right) > 0; }
inline bool operator>(const std::basic_string<T> &right)const{ return this->compare(right) > 0; } inline bool operator>(const std::basic_string<T> &right)const{ return this->compare(right) > 0; }
inline bool operator>(const T *right)const{ return this->compare(right) > 0; }
inline bool operator>(const T right)const{ return this->compare(right) > 0; } inline bool operator>(const T right)const{ return this->compare(right) > 0; }
inline bool operator<=(const Readable_String<T> &right)const{ return !operator>(right); } inline bool operator<=(const Readable_String<T> &right)const{ return !operator>(right); }
inline bool operator<=(const std::basic_string<T> &right)const{ return !operator>(right); } inline bool operator<=(const std::basic_string<T> &right)const{ return !operator>(right); }
inline bool operator<=(const T *right)const{ return !operator>(right); }
inline bool operator<=(const T right)const{ return !operator>(right); } inline bool operator<=(const T right)const{ return !operator>(right); }
inline bool operator>=(const Readable_String<T> &right)const{ return !operator<(right); } inline bool operator>=(const Readable_String<T> &right)const{ return !operator<(right); }
inline bool operator>=(const std::basic_string<T> &right)const{ return !operator<(right); } inline bool operator>=(const std::basic_string<T> &right)const{ return !operator<(right); }
inline bool operator>=(const T *right)const{ return !operator<(right); }
inline bool operator>=(const T right)const{ return !operator<(right); } inline bool operator>=(const T right)const{ return !operator<(right); }
/** Conversion operators */ /** Conversion operators */

238
src/include/Jupiter/Readable_String_Imp.h

@ -33,18 +33,6 @@
* Readable_String * Readable_String
*/ */
// isEmpty
template<typename T> bool Jupiter::Readable_String<T>::isEmpty() const
{
return this->size() == 0;
}
template<typename T> bool Jupiter::Readable_String<T>::isNotEmpty() const
{
return this->size() != 0;
}
// contains // contains
template<typename T> bool Jupiter::Readable_String<T>::contains(const T &value) const template<typename T> bool Jupiter::Readable_String<T>::contains(const T &value) const
@ -73,7 +61,7 @@ template<typename T> size_t Jupiter::Readable_String<T>::find(const Jupiter::Rea
if (in.size() > this->size()) if (in.size() > this->size())
return Jupiter::INVALID_INDEX; return Jupiter::INVALID_INDEX;
if (in.size() == this->size()) if (in.size() == this->size())
return this->equals(in) ? 0 : Jupiter::INVALID_INDEX; return (*this == in) ? 0 : Jupiter::INVALID_INDEX;
if (in.isEmpty()) if (in.isEmpty())
return 0; return 0;
@ -86,82 +74,6 @@ template<typename T> size_t Jupiter::Readable_String<T>::find(const Jupiter::Rea
return Jupiter::INVALID_INDEX; return Jupiter::INVALID_INDEX;
} }
// findi
template<> size_t inline Jupiter::Readable_String<char>::findi(const char &value, size_t index) const
{
const char upperValue = (const char) toupper(value);
for (size_t i = 0; i != this->size(); i++)
{
if (toupper(this->get(i)) == upperValue)
{
if (index == 0) return i;
else index--;
}
}
return Jupiter::INVALID_INDEX;
}
template<> size_t inline Jupiter::Readable_String<wchar_t>::findi(const wchar_t &value, size_t index) const
{
const wchar_t upperValue = towupper(value);
for (size_t i = 0; i != this->size(); i++)
{
if (towupper(this->get(i)) == upperValue)
{
if (index == 0) return i;
else index--;
}
}
return Jupiter::INVALID_INDEX;
}
template<typename T> size_t Jupiter::Readable_String<T>::findi(const T &value, size_t index) const
{
return Jupiter::INVALID_INDEX;
}
template<> size_t inline Jupiter::Readable_String<char>::findi(const Jupiter::Readable_String<char> &in) const
{
if (in.size() > this->size())
return Jupiter::INVALID_INDEX;
if (in.size() == this->size())
return this->equalsi(in) ? 0 : Jupiter::INVALID_INDEX;
if (in.isEmpty())
return 0;
for (size_t i = 0, j; i != this->size() - in.size() + 1; i++)
{
j = 0;
while (toupper(this->get(i + j)) == toupper(in.get(j)))
if (++j == in.size()) return i;
}
return Jupiter::INVALID_INDEX;
}
template<> size_t inline Jupiter::Readable_String<wchar_t>::findi(const Jupiter::Readable_String<wchar_t> &in) const
{
if (in.size() > this->size())
return Jupiter::INVALID_INDEX;
if (in.size() == this->size())
return this->equalsi(in) ? 0 : Jupiter::INVALID_INDEX;
if (in.isEmpty())
return 0;
for (size_t i = 0, j; i != this->size() - in.size() + 1; i++)
{
j = 0;
while (towupper(this->get(i + j)) == towupper(in.get(j)))
if (++j == in.size()) return i;
}
return Jupiter::INVALID_INDEX;
}
template<typename T> size_t Jupiter::Readable_String<T>::findi(const Jupiter::Readable_String<T> &) const
{
return Jupiter::INVALID_INDEX;
}
// span() // span()
template<typename T> size_t Jupiter::Readable_String<T>::span(const Jupiter::Readable_String<T> &in) const template<typename T> size_t Jupiter::Readable_String<T>::span(const Jupiter::Readable_String<T> &in) const
@ -188,118 +100,6 @@ template<typename T> size_t Jupiter::Readable_String<T>::span(const T &in) const
return index; return index;
} }
// compare()
template<typename T> int Jupiter::Readable_String<T>::compare(const Jupiter::Readable_String<T> &in) const
{
// rewrite to compare multiple bytes at a time.
size_t index = 0;
while (this->get(index) == in.get(index))
{
index++;
if (index == in.size())
{
if (index == this->size()) return 0;
return 1;
}
if (index == this->size()) return 0 - in.get(index);
}
return this->get(index) - in.get(index);
}
template<typename T> int Jupiter::Readable_String<T>::compare(const std::basic_string<T> &in) const
{
// rewrite to compare multiple bytes at a time.
size_t index = 0;
while (this->get(index) == in.at(index))
{
index++;
if (index == in.size())
{
if (index == this->size()) return 0;
return 1;
}
if (index == this->size()) return 0 - in.at(index);
}
return this->get(index) - in.at(index);
}
template<typename T> int Jupiter::Readable_String<T>::compare(const T *s2) const
{
if (this->size() == 0) return 0 - *s2;
size_t index = 0;
while (this->get(index) == *s2)
{
index++;
if (*s2 == 0)
{
if (index == this->size()) return 0;
return 1;
}
s2++;
if (index == this->size()) return 0 - *s2;
}
return this->get(index) - *s2;
}
template<typename T> int Jupiter::Readable_String<T>::compare(const T &in) const
{
if (this->size() == 0) return 0 - in;
return this->get(0) - in;
}
template<typename T> int Jupiter::Readable_String<T>::compare(const std::nullptr_t) const
{
if (this->size() == 0) return true;
return this->get(0);
}
// equals()
template<typename T> bool Jupiter::Readable_String<T>::equals(const Jupiter::Readable_String<T> &in) const
{
return this->equals(in.ptr(), in.size());
}
template<typename T> bool Jupiter::Readable_String<T>::equals(const std::basic_string<T> &in) const
{
return this->equals(in.data(), in.size());
}
template<typename T> bool Jupiter::Readable_String<T>::equals(const T *in, size_t len) const
{
if (this->size() != len)
return false;
// rewrite to compare multiple bytes at a time.
in += len;
while (len != 0)
if (this->get(--len) != *(--in))
return false;
return true;
}
template<typename T> bool Jupiter::Readable_String<T>::equals(const T *in) const
{
if (in == nullptr) return this->isEmpty();
for (size_t index = 0; index != this->size(); index++)
{
if (*in == 0 || this->get(index) != *in) return false;
in++;
}
return *in == 0;
}
template<typename T> bool Jupiter::Readable_String<T>::equals(const T &in) const
{
return this->size() == 1 && this->get(0) == in;
}
template<typename T> bool Jupiter::Readable_String<T>::equals(std::nullptr_t) const
{
return this->size() == 0;
}
// equalsi() // equalsi()
template<typename T> bool Jupiter::Readable_String<T>::equalsi(const Jupiter::Readable_String<T> &in) const template<typename T> bool Jupiter::Readable_String<T>::equalsi(const Jupiter::Readable_String<T> &in) const
@ -339,34 +139,7 @@ template<> bool inline Jupiter::Readable_String<wchar_t>::equalsi(const wchar_t
template<typename T> bool Jupiter::Readable_String<T>::equalsi(const T *in, size_t len) const template<typename T> bool Jupiter::Readable_String<T>::equalsi(const T *in, size_t len) const
{ {
return this->equals(in); // Concept of "case" not supported for type. return *this == std::basic_string_view<T>(in); // Concept of "case" not supported for type.
}
template<> bool inline Jupiter::Readable_String<char>::equalsi(const char *in) const
{
if (in == nullptr) return this->size() == 0;
for (size_t index = 0; index != this->size(); index++)
{
if (*in == 0 || toupper(this->get(index)) != toupper(*in)) return false;
in++;
}
return *in == 0;
}
template<> bool inline Jupiter::Readable_String<wchar_t>::equalsi(const wchar_t *in) const
{
if (in == nullptr) return this->size() == 0;
for (size_t index = 0; index != this->size(); index++)
{
if (*in == 0 || towupper(this->get(index)) != towupper(*in)) return false;
in++;
}
return *in == 0;
}
template<typename T> bool Jupiter::Readable_String<T>::equalsi(const T *in) const
{
return this->equals(in); // Concept of "case" not supported for type.
} }
template<> bool inline Jupiter::Readable_String<char>::equalsi(const char &in) const template<> bool inline Jupiter::Readable_String<char>::equalsi(const char &in) const
@ -381,12 +154,7 @@ template<> bool inline Jupiter::Readable_String<wchar_t>::equalsi(const wchar_t
template<typename T> bool Jupiter::Readable_String<T>::equalsi(const T &in) const template<typename T> bool Jupiter::Readable_String<T>::equalsi(const T &in) const
{ {
return this->equals(in); // Concept of "case" not supported for type. return *this == in; // Concept of "case" not supported for type.
}
template<typename T> bool Jupiter::Readable_String<T>::equalsi(const std::nullptr_t) const
{
return this->size() == 0;
} }
// match() // match()

4
src/include/Jupiter/SecureSocket.h

@ -79,7 +79,7 @@ namespace Jupiter
* @param key String containing file location of private key. * @param key String containing file location of private key.
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
void setCertificate(const Jupiter::ReadableString &cert, const Jupiter::ReadableString &key); void setCertificate(std::string cert, std::string key);
/** /**
* @brief Loads a certificate and key for use. * @brief Loads a certificate and key for use.
@ -87,7 +87,7 @@ namespace Jupiter
* @param pem Combined certificate/key file. * @param pem Combined certificate/key file.
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
void setCertificate(const Jupiter::ReadableString &pem); void setCertificate(std::string_view pem);
/** /**
* @brief Interface to provide simple connection establishing. * @brief Interface to provide simple connection establishing.

15
src/include/Jupiter/String.hpp

@ -456,6 +456,21 @@ namespace Jupiter
return static_cast<size_t>(Jupiter::fnv1a_32<char>(in)); return static_cast<size_t>(Jupiter::fnv1a_32<char>(in));
} }
}; };
template<typename CharT>
struct str_hash {
using is_transparent = std::true_type;
// C++17 introduces a requirement that these two operators return the same values for same CharT type, but not
// any requirement that std::hash<> be able to accept both key types. This just ties them for convenience
auto operator()(std::basic_string_view<CharT> in_key) const noexcept {
return std::hash<std::basic_string_view<CharT>>()(in_key);
}
auto operator()(const std::basic_string<CharT>& in_key) const noexcept {
return std::hash<std::basic_string<CharT>>()(in_key);
}
};
} }
/** Re-enable warning */ /** Re-enable warning */

2
src/include/Jupiter/String_Type.h

@ -192,6 +192,7 @@ namespace Jupiter
virtual size_t replace(size_t index, size_t length, const T &value); virtual size_t replace(size_t index, size_t length, const T &value);
virtual size_t replace(size_t index, size_t length, const T *value, size_t valueSize); virtual size_t replace(size_t index, size_t length, const T *value, size_t valueSize);
virtual size_t replace(size_t index, size_t length, const Jupiter::Readable_String<T> &value); virtual size_t replace(size_t index, size_t length, const Jupiter::Readable_String<T> &value);
virtual size_t replace(size_t index, size_t length, std::basic_string_view<T> value);
/** /**
* @brief Replaces all instances of one value with another value. * @brief Replaces all instances of one value with another value.
@ -211,6 +212,7 @@ namespace Jupiter
virtual size_t replace(const T *target, size_t targetSize, const Jupiter::Readable_String<T> &value); virtual size_t replace(const T *target, size_t targetSize, const Jupiter::Readable_String<T> &value);
virtual size_t replace(const Jupiter::Readable_String<T> &target, const T *value, size_t valueSize); virtual size_t replace(const Jupiter::Readable_String<T> &target, const T *value, size_t valueSize);
virtual size_t replace(const Jupiter::Readable_String<T> &target, const Jupiter::Readable_String<T> &value); virtual size_t replace(const Jupiter::Readable_String<T> &target, const Jupiter::Readable_String<T> &value);
virtual size_t replace(std::basic_string_view<T> target, std::basic_string_view<T> value);
/** /**
* @brief Copies the data from the input string and concatenates it to the end of String. * @brief Copies the data from the input string and concatenates it to the end of String.

16
src/include/Jupiter/String_Type_Imp.h

@ -553,11 +553,14 @@ template<typename T> size_t Jupiter::String_Type<T>::replace(size_t index, size_
return Jupiter::String_Type<T>::length; return Jupiter::String_Type<T>::length;
} }
template<typename T> size_t Jupiter::String_Type<T>::replace(size_t index, size_t targetSize, const Jupiter::Readable_String<T> &value) template<typename T> size_t Jupiter::String_Type<T>::replace(size_t index, size_t targetSize, const Jupiter::Readable_String<T> &value) {
{
return this->replace(index, targetSize, value.ptr(), value.size()); return this->replace(index, targetSize, value.ptr(), value.size());
} }
template<typename T> size_t Jupiter::String_Type<T>::replace(size_t index, size_t targetSize, std::basic_string_view<T> value) {
return this->replace(index, targetSize, value.data(), value.size());
}
template<typename T> size_t Jupiter::String_Type<T>::replace(const T &target, const T &value) template<typename T> size_t Jupiter::String_Type<T>::replace(const T &target, const T &value)
{ {
for (size_t i = 0; i != Jupiter::String_Type<T>::length; i++) for (size_t i = 0; i != Jupiter::String_Type<T>::length; i++)
@ -599,7 +602,7 @@ template<typename T> size_t Jupiter::String_Type<T>::replace(const T *target, si
Jupiter::String_Type<T>::length = i; Jupiter::String_Type<T>::length = i;
} }
else if (targetSize == Jupiter::String_Type<T>::length && this->equals(target, targetSize)) else if (targetSize == Jupiter::String_Type<T>::length && *this == std::basic_string_view<T>(target, targetSize))
return this->set(value); return this->set(value);
} }
return Jupiter::String_Type<T>::length; return Jupiter::String_Type<T>::length;
@ -702,7 +705,7 @@ template<typename T> size_t Jupiter::String_Type<T>::replace(const T *target, si
Jupiter::String_Type<T>::length = i; Jupiter::String_Type<T>::length = i;
} }
} }
else if (targetSize == Jupiter::String_Type<T>::length && this->equals(target, targetSize)) else if (targetSize == Jupiter::String_Type<T>::length && *this == std::basic_string_view<T>(target, targetSize))
return this->set(value); return this->set(value);
} }
return Jupiter::String_Type<T>::length; return Jupiter::String_Type<T>::length;
@ -723,6 +726,11 @@ template<typename T> size_t Jupiter::String_Type<T>::replace(const Jupiter::Read
return this->replace(target.ptr(), target.size(), value.ptr(), value.size()); return this->replace(target.ptr(), target.size(), value.ptr(), value.size());
} }
template<typename T> size_t Jupiter::String_Type<T>::replace(std::basic_string_view<T> target, std::basic_string_view<T> value)
{
return this->replace(target.data(), target.size(), value.data(), value.size());
}
// concat // concat
template<typename T> size_t Jupiter::String_Type<T>::concat(const T *in, size_t inSize) template<typename T> size_t Jupiter::String_Type<T>::concat(const T *in, size_t inSize)

2
src/jessilib

@ -1 +1 @@
Subproject commit 9d5d8b0abba01eaccd15d79ef63d2f7d13e94b50 Subproject commit f714a1da00dfd9f1f6ef9a8350099318ddd4734e
Loading…
Cancel
Save