I created a class to add functionality to c++ std::string
(std::basic_string
actually), let's call it String
.
I would like to know, what changes to do to String
to boost it performance. Maybe having an internal std::basic_string
member is not the best idea and it would be better to implement my own (that maybe would be re-inventing the wheel) or maybe the class itself is just not necessary and would be better just to write down functions under a namespace.
That being said, here is the code:
String.h
#pragma once
#include <string>
template <class CharType = wchar_t>
class String {
public:
String();
String(const CharType*);
String(std::basic_string<CharType>);
~String();
std::size_t length();
std::size_t size();
std::size_t bytesize();
std::string to_bytes();
static std::basic_string<CharType> from_bytes(const char*);
static std::basic_string<CharType> from_bytes(std::string);
std::basic_string<CharType> std;
};
String.cpp
#include "String.h"
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
// Default constructor with no parameters
template <class CharType>
String<CharType>::String() { }
// Constructor for:
// String<char> variable = "Hi there";
// String<char16_t> variable = u"Hi there";
template <class CharType>
String<CharType>::String(const CharType* str): std(str) { }
// Normal Constructor
// String<char> variable("Hi there");
// String<char16_t> variable(u"Hi there");
template <class CharType>
String<CharType>::String(std::basic_string<CharType> str): std(str) { }
// Destructor
template <class CharType>
String<CharType>::~String() { }
// Get the length of a string, it's not necessary to calculate it
// since std::string already provides this functionality
template <class CharType>
std::size_t String<CharType>::length() {
return std.length();
}
// Now, in a string of `char` the length would be different of expected
// as actually it counts special characters by its number of bytesize
// with this functionality it counts those characters as one
// Demonstration
// std::char_traits<char>::length("Ni hao 你好")
// ^ 13 since each chinese character counts as 3
//
// String<char>("Ni hao 你好").length();
// ^ 9 as expected
//
// Default ::length() functionality can be accesed through `std` member
// Example:
// String<char>("Ni hao 你好").std.length();
// ^ 13
template <>
std::size_t String<char>::length() {
return String<char32_t>::from_bytes(std.c_str()).length();
}
// Use already implemented functinality from std::string
template <class CharType>
std::size_t String<CharType>::size() {
return std.size();
}
// Convert string special character to bytes and count
template <class CharType>
std::size_t String<CharType>::bytesize() {
return to_bytes().size();
}
// Convert the actual string into byte representation
template <class CharType>
std::string String<CharType>::to_bytes() {
std::wstring_convert<std::codecvt_utf8_utf16<CharType>, CharType> converter;
return converter.to_bytes(std);
}
// `char` doesn't need to convert, so return itself
template <> std::string String<char>::to_bytes() {
return std;
}
// Create a new wide characters string using a bytes string
template <class CharType>
std::basic_string<CharType> String<CharType>::from_bytes(const char* str) {
std::wstring_convert<std::codecvt_utf8<CharType>, CharType> converter;
return converter.from_bytes(str);
}
template <>
std::basic_string<char16_t> String<char16_t>::from_bytes(const char* str) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
return converter.from_bytes(str);
}
// When creating from bytes inside of a std::string
template <class CharType>
std::basic_string<CharType> String<CharType>::from_bytes(std::string str) {
return String<CharType>::from_bytes(str.data());
}
// Needs to be implemented to prevent errors between `std::codecvt` and `char`
template <>
std::basic_string<char> String<char>::from_bytes(const char* str) {
return str;
}
// Why would anyone include a .cpp file
template class String<char>;
template class String<wchar_t>;
template class String<char16_t>;
template class String<char32_t>;
Example of usage:
const char* text = "Hi there \u270c\u270c";
String<wchar_t> test_wchar = String<wchar_t>::from_bytes(text);
test_wchar.bytesize();
test_wchar.length();
test_wchar.std // this member is std::basic_string<wchar_t>
std::wstring
, but provide overloaded (non-member) functions that compute theactual_length(std::basic_string<T>)
etc. That way, you maintain the full advantage of all functionality provided by thestd
library (iterators etc) and only explicitly add the functionality you actually want. \$\endgroup\$