Merge pull request #473 from oatpp/string_convenience_improvement

oatpp::String: better convenience methods.
This commit is contained in:
Leonid Stryzhevskyi 2021-08-25 01:14:11 +03:00 committed by GitHub
commit 92b5a444d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 216 additions and 99 deletions

View File

@ -26,6 +26,9 @@
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/core/utils/ConversionUtils.hpp"
#include "oatpp/core/data/share/MemoryLabel.hpp"
#include <fstream>
namespace oatpp { namespace data { namespace mapping { namespace type {
@ -36,7 +39,46 @@ String::String(const std::shared_ptr<std::string>& ptr, const type::Type* const
throw std::runtime_error("Value type does not match");
}
}
String String::loadFromFile(const char* filename) {
std::ifstream file (filename, std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open()) {
auto result = data::mapping::type::String(file.tellg());
file.seekg(0, std::ios::beg);
file.read((char*) result->data(), result->size());
file.close();
return result;
}
return nullptr;
}
void String::saveToFile(const char* filename) const {
std::ofstream fs(filename, std::ios::out | std::ios::binary);
if(m_ptr != nullptr) {
fs.write(m_ptr->data(), m_ptr->size());
}
fs.close();
}
const std::string& String::operator*() const {
return this->m_ptr.operator*();
}
bool String::equalsCI_ASCII(const std::string& other) {
auto ciLabel = share::StringKeyLabelCI(m_ptr);
return ciLabel == other;
}
bool String::equalsCI_ASCII(const String& other) {
auto ciLabel = share::StringKeyLabelCI(m_ptr);
return ciLabel == other;
}
bool String::equalsCI_ASCII(const char* other) {
auto ciLabel = share::StringKeyLabelCI(m_ptr);
return ciLabel == other;
}
String operator + (const char* a, const String& b) {
data::stream::BufferOutputStream stream;
stream << a << b;

View File

@ -123,14 +123,26 @@ public:
: type::ObjectWrapper<std::string, __class::String>(std::forward<String>(other))
{}
const std::string& operator*() const {
if (this->m_ptr == nullptr) throw std::runtime_error("[oatpp::data::mapping::type::String] Error: m_ptr points to null.");
return this->m_ptr.operator*();
}
/**
* Load data from file and store in &id:oatpp::String;.
* @param filename - name of the file.
* @return - &id:oatpp::String;.
*/
static String loadFromFile(const char* filename);
operator std::string() const
{
if (this->m_ptr == nullptr) throw std::runtime_error("[oatpp::data::mapping::type::String] Error: m_ptr points to null.");
/**
* Save content of the buffer to file.
* @param filename - name of the file.
*/
void saveToFile(const char* filename) const;
const std::string& operator*() const;
operator std::string() const {
if (this->m_ptr == nullptr) {
throw std::runtime_error("[oatpp::data::mapping::type::String::operator std::string() const]: "
"Error. Null pointer.");
}
return this->m_ptr.operator*();
}
@ -176,41 +188,26 @@ public:
return *this;
}
/**
* Case insensitive compare (ASCII only).
* @param other
* @return
*/
bool equalsCI_ASCII(const std::string& other);
inline bool equalsCI(const std::string &sb) {
if (this->m_ptr == nullptr ) return false;
const std::string& sa = this->m_ptr.operator*();
return (sa.size() == sb.size()) && std::equal(sa.begin(), sa.end(), sb.begin(),
[] (char a, char b) -> bool {
return std::tolower(a) == std::tolower(b);
});
}
/**
* Case insensitive compare (ASCII only).
* @param other
* @return
*/
bool equalsCI_ASCII(const String& other);
inline bool equalsCI(const String &b) {
if (this->m_ptr == nullptr && b.m_ptr == nullptr) return true;
if (this->m_ptr == nullptr && b.m_ptr != nullptr) return false;
if (this->m_ptr != nullptr && b.m_ptr == nullptr) return false;
const std::string& sb = *b;
return this->equalsCI(sb);
}
inline bool equalsCI(const char *b) {
if (this->m_ptr == nullptr && b == nullptr) return true;
if (this->m_ptr == nullptr && b != nullptr) return false;
if (this->m_ptr != nullptr && b == nullptr) return false;
size_t lb = strlen(b);
const std::string& sa = this->m_ptr.operator*();
if (sa.size() != lb) return false;
const char *ba = b;
for ( const auto &ca: sa ) {
if ( std::tolower(ca) != std::tolower(*ba)) return false;
ba++;
}
return true;
}
/**
* Case insensitive compare (ASCII only).
* @param other
* @return
*/
bool equalsCI_ASCII(const char* str);
template<typename T,
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type

View File

@ -25,6 +25,8 @@
#ifndef oatpp_data_share_MemoryLabel_hpp
#define oatpp_data_share_MemoryLabel_hpp
#include <memory>
#include "oatpp/core/data/mapping/type/Primitive.hpp"
#include "oatpp/core/utils/String.hpp"
@ -64,9 +66,15 @@ public:
/**
* Constructor.
* @param str
* @param ptr
*/
MemoryLabel(const std::shared_ptr<std::string>& str) : MemoryLabel(str, str->data(), (v_buff_size) str->size()) {}
MemoryLabel(const std::shared_ptr<std::string>& ptr) :
MemoryLabel(
ptr,
ptr ? ptr->data() : nullptr,
ptr ? (v_buff_size) ptr->size() : 0
)
{}
/**
* Constructor.
@ -105,7 +113,7 @@ public:
*/
void captureToOwnMemory() const {
if(!m_memoryHandle || m_memoryHandle->data() != (const char*)m_data || m_memoryHandle->size() != m_size) {
m_memoryHandle.reset(new std::string((const char*) m_data, m_size));
m_memoryHandle = std::make_shared<std::string>((const char*) m_data, m_size);
m_data = (p_char8) m_memoryHandle->data();
}
}
@ -117,7 +125,8 @@ public:
* @return - `true` if equals.
*/
bool equals(const char* data) const {
return utils::String::compare(m_data, m_size, data, std::strlen(data)) == 0;
auto len = data != nullptr ? std::strlen(data) : 0;
return utils::String::compare(m_data, m_size, data, len) == 0;
}
/**
@ -170,7 +179,13 @@ public:
StringKeyLabel() : MemoryLabel() {};
StringKeyLabel(std::nullptr_t) : MemoryLabel() {}
/**
* Constructor.
* @param ptr
*/
StringKeyLabel(const std::shared_ptr<std::string>& ptr) : MemoryLabel(ptr) {}
StringKeyLabel(const std::shared_ptr<std::string>& memoryHandle, const char* data, v_buff_size size);
StringKeyLabel(const char* constText);
StringKeyLabel(const String& str);
@ -229,6 +244,8 @@ public:
StringKeyLabelCI(std::nullptr_t) : MemoryLabel() {}
StringKeyLabelCI(const std::shared_ptr<std::string>& ptr) : MemoryLabel(ptr) {}
StringKeyLabelCI(const std::shared_ptr<std::string>& memoryHandle, const char* data, v_buff_size size);
StringKeyLabelCI(const char* constText);
StringKeyLabelCI(const String& str);
@ -242,7 +259,8 @@ public:
}
inline bool operator==(const char* str) const {
return utils::String::compareCI(m_data, m_size, str, std::strlen(str)) == 0;
auto len = str != nullptr ? std::strlen(str) : 0;
return utils::String::compareCI_ASCII(m_data, m_size, str, len) == 0;
}
inline bool operator!=(const char* str) const {
@ -252,7 +270,7 @@ public:
inline bool operator==(const String& str) const {
if(m_data == nullptr) return str == nullptr;
if(str == nullptr) return false;
return utils::String::compareCI(m_data, m_size, str->data(), str->size()) == 0;
return utils::String::compareCI_ASCII(m_data, m_size, str->data(), str->size()) == 0;
}
inline bool operator!=(const String& str) const {
@ -260,7 +278,7 @@ public:
}
inline bool operator==(const StringKeyLabelCI &other) const {
return utils::String::compareCI(m_data, m_size, other.m_data, other.m_size) == 0;
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) == 0;
}
inline bool operator!=(const StringKeyLabelCI &other) const {
@ -268,11 +286,11 @@ public:
}
inline bool operator < (const StringKeyLabelCI &other) const {
return utils::String::compareCI(m_data, m_size, other.m_data, other.m_size) < 0;
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) < 0;
}
inline bool operator > (const StringKeyLabelCI &other) const {
return utils::String::compareCI(m_data, m_size, other.m_data, other.m_size) > 0;
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) > 0;
}
};
@ -289,7 +307,7 @@ namespace std {
result_type operator()(oatpp::data::share::StringKeyLabel const& s) const noexcept {
p_char8 data = (p_char8) s.getData();
auto data = (p_char8) s.getData();
result_type result = 0;
for(v_buff_size i = 0; i < s.getSize(); i++) {
v_char8 c = data[i];
@ -309,7 +327,7 @@ namespace std {
result_type operator()(oatpp::data::share::StringKeyLabelCI const& s) const noexcept {
p_char8 data = (p_char8) s.getData();
auto data = (p_char8) s.getData();
result_type result = 0;
for(v_buff_size i = 0; i < s.getSize(); i++) {
v_char8 c = data[i] | 32;

View File

@ -23,29 +23,10 @@
***************************************************************************/
#include "String.hpp"
#include <fstream>
#include <cstring>
namespace oatpp { namespace utils {
data::mapping::type::String String::loadFromFile(const char* filename) {
std::ifstream file (filename, std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open()) {
auto result = data::mapping::type::String(file.tellg());
file.seekg(0, std::ios::beg);
file.read((char*) result->data(), result->size());
file.close();
return result;
}
return nullptr;
}
void String::saveToFile(const data::mapping::type::String& data, const char* filename) {
std::ofstream fs(filename, std::ios::out | std::ios::binary);
fs.write(data->data(), data->size());
fs.close();
}
v_buff_size String::compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
if(data1 == data2) return 0;
@ -68,7 +49,7 @@ v_buff_size String::compare(const void* data1, v_buff_size size1, const void* da
}
v_buff_size String::compareCI(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
v_buff_size String::compareCI_ASCII(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
if(data1 == data2) return 0;
if(data1 == nullptr) return -1;
@ -101,14 +82,14 @@ v_buff_size String::compareCI(const void* data1, v_buff_size size1, const void*
}
void String::lowerCaseASCII(void* data, v_buff_size size) {
void String::lowerCase_ASCII(void* data, v_buff_size size) {
for(v_buff_size i = 0; i < size; i++) {
v_char8 a = ((p_char8) data)[i];
if(a >= 'A' && a <= 'Z') ((p_char8) data)[i] = a | 32;
}
}
void String::upperCaseASCII(void* data, v_buff_size size) {
void String::upperCase_ASCII(void* data, v_buff_size size) {
for(v_buff_size i = 0; i < size; i++) {
v_char8 a = ((p_char8) data)[i];
if(a >= 'a' && a <= 'z') ((p_char8) data)[i] = a & 223;

View File

@ -25,7 +25,6 @@
#ifndef oatpp_utils_String_hpp
#define oatpp_utils_String_hpp
#include "oatpp/core/data/mapping/type/Primitive.hpp"
#include "oatpp/core/base/Environment.hpp"
namespace oatpp { namespace utils {
@ -36,19 +35,6 @@ namespace oatpp { namespace utils {
class String {
public:
/**
* Load data from file and store in &id:oatpp::String;.
* @param filename - name of the file.
* @return - &id:oatpp::String;.
*/
static data::mapping::type::String loadFromFile(const char* filename);
/**
* Save content of the buffer to file.
* @param filename - name of the file.
*/
static void saveToFile(const data::mapping::type::String& data, const char* filename);
/**
* Compare data1, data2 using `std::memcmp`.
* *It's safe to pass nullptr for data1/data2*
@ -63,7 +49,7 @@ public:
static v_buff_size compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
/**
* Compare data1, data2 - case insensitive.
* Compare data1, data2 - case insensitive (ASCII only).
* *It's safe to pass nullptr for data1/data2*
* @param data1 - pointer to data1.
* @param size1 - size of data1.
@ -73,21 +59,21 @@ public:
* 0 if all count bytes of data1 and data2 are equal.<br>
* Positive value if the first differing byte in data1 is greater than the corresponding byte in data2.
*/
static v_buff_size compareCI(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
static v_buff_size compareCI_ASCII(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
/**
* Change characters in data to lowercase (ASCII only).
* @param data - pointer to data.
* @param size - size of the data.
*/
static void lowerCaseASCII(void* data, v_buff_size size);
static void lowerCase_ASCII(void* data, v_buff_size size);
/**
* Change characters in data to uppercase (ASCII only).
* @param data - pointer to data.
* @param size - size of the data.
*/
static void upperCaseASCII(void* data, v_buff_size size);
static void upperCase_ASCII(void* data, v_buff_size size);
};

View File

@ -35,7 +35,7 @@ oatpp::String Url::Parser::parseScheme(oatpp::parser::Caret& caret) {
if(size > 0) {
std::unique_ptr<v_char8[]> buff(new v_char8[size]);
std::memcpy(buff.get(), &caret.getData()[pos0], size);
utils::String::lowerCaseASCII(buff.get(), size);
utils::String::lowerCase_ASCII(buff.get(), size);
return oatpp::String((const char*)buff.get(), size);
}
return nullptr;

View File

@ -72,7 +72,7 @@ void SchemaMigration::migrate() {
break;
case SOURCE_FILE:
script = utils::String::loadFromFile(source.param->c_str());
script = oatpp::String::loadFromFile(source.param->c_str());
break;
default:

View File

@ -55,7 +55,7 @@ void CommunicationUtils::considerConnectionState(const std::shared_ptr<protocol:
/* Set HTTP/1.1 default Connection header value (Keep-Alive), if no Connection header present in response. */
/* Set keep-alive to value specified in response otherwise */
auto& protocol = request->getStartingLine().protocol;
if(protocol && oatpp::utils::String::compareCI(protocol.getData(), protocol.getSize(), "HTTP/1.1", 8) == 0) {
if(protocol && oatpp::utils::String::compareCI_ASCII(protocol.getData(), protocol.getSize(), "HTTP/1.1", 8) == 0) {
if(outState && outState != Header::Value::CONNECTION_KEEP_ALIVE) {
connectionState = ConnectionState::CLOSING;
}

View File

@ -93,7 +93,7 @@ public:
ProcessorToUpper(v_int32 bufferSize) : BaseProcessor(bufferSize) {}
void process(p_char8 data, v_buff_size size) override {
utils::String::upperCaseASCII(data, size);
utils::String::upperCase_ASCII(data, size);
}
};
@ -104,7 +104,7 @@ public:
ProcessorToLower(v_int32 bufferSize) : BaseProcessor(bufferSize) {}
void process(p_char8 data, v_buff_size size) override {
utils::String::lowerCaseASCII(data, size);
utils::String::lowerCase_ASCII(data, size);
}
};

View File

@ -221,6 +221,99 @@ void StringTest::onRun() {
OATPP_LOGI(TAG, "OK");
}
{
OATPP_LOGI(TAG, "test compareCI_ASCII methods 1");
oatpp::String s1 = "hello";
{
oatpp::String s2;
OATPP_ASSERT(!s1.equalsCI_ASCII(s2));
}
{
const char* s2 = nullptr;
OATPP_ASSERT(!s1.equalsCI_ASCII(s2));
}
}
{
OATPP_LOGI(TAG, "test compareCI_ASCII methods 2");
oatpp::String s1;
{
oatpp::String s2 = "hello";
OATPP_ASSERT(!s1.equalsCI_ASCII(s2));
}
{
std::string s2 = "hello";
OATPP_ASSERT(!s1.equalsCI_ASCII(s2));
}
{
const char* s2 = "hello";
OATPP_ASSERT(!s1.equalsCI_ASCII(s2));
}
{
oatpp::String s2;
OATPP_ASSERT(s1.equalsCI_ASCII(s2));
}
{
const char* s2 = nullptr;
OATPP_ASSERT(s1.equalsCI_ASCII(s2));
}
{
OATPP_ASSERT(s1.equalsCI_ASCII(nullptr));
}
{
bool exceptionThrown = false;
try {
std::string s2 = s1;
} catch (const std::runtime_error& e) {
exceptionThrown = true;
}
OATPP_ASSERT(exceptionThrown);
}
}
{
OATPP_LOGI(TAG, "test compareCI_ASCII methods 3");
oatpp::String s1 = "hello";
{
oatpp::String s2 = "HELLO";
OATPP_ASSERT(s1.equalsCI_ASCII(s2));
}
{
std::string s2 = "HELLO";
OATPP_ASSERT(s1.equalsCI_ASCII(s2));
}
{
const char* s2 = "HELLO";
OATPP_ASSERT(s1.equalsCI_ASCII(s2));
}
{
OATPP_ASSERT(s1.equalsCI_ASCII("HELLO"));
}
}
}
}}}}}}