Use drogon::OStringStream instead of std::stringstream in text template (#322)

This commit is contained in:
An Tao 2020-01-01 16:15:11 +08:00 committed by GitHub
parent feb0b73e78
commit 1c99a8a94e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 212 additions and 9 deletions

View File

@ -425,7 +425,8 @@ set(DROGON_UTIL_HEADERS
lib/inc/drogon/utils/Utilities.h
lib/inc/drogon/utils/any.h
lib/inc/drogon/utils/string_view.h
lib/inc/drogon/utils/HttpConstraint.h)
lib/inc/drogon/utils/HttpConstraint.h
lib/inc/drogon/utils/OStringStream.h)
install(FILES ${DROGON_UTIL_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)

View File

@ -330,8 +330,8 @@ void create_view::newViewSourceFile(std::ofstream &file,
file << "//this file is generated by program(drogon_ctl) "
"automatically,don't modify it!\n";
file << "#include \"" << className << ".h\"\n";
file << "#include <drogon/utils/OStringStream.h>\n";
file << "#include <string>\n";
file << "#include <sstream>\n";
file << "#include <map>\n";
file << "#include <vector>\n";
file << "#include <set>\n";
@ -416,7 +416,7 @@ void create_view::newViewSourceFile(std::ofstream &file,
std::string streamName = className + "_tmp_stream";
// oSrcFile <<"\tstd::string "<<bodyName<<";\n";
file << "\tstd::stringstream " << streamName << ";\n";
file << "\tdrogon::OStringStream " << streamName << ";\n";
int cxx_flag = 0;
while (infile.getline(line, sizeof(line)))
{
@ -428,6 +428,6 @@ void create_view::newViewSourceFile(std::ofstream &file,
}
parseLine(file, buffer, streamName, viewDataName, cxx_flag);
}
file << "return " << streamName << ".str();\n}\n";
file << "std::string ret{std::move(" << streamName << ".str())};\n";
file << "return ret;\n}\n";
}

View File

@ -0,0 +1,140 @@
/**
*
* OStringStream.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <string>
#include <sstream>
#include <drogon/utils/string_view.h>
namespace drogon
{
namespace internal
{
template <typename T>
struct CanConvertToString
{
using Type = std::remove_reference_t<std::remove_cv_t<T>>;
private:
using yes = std::true_type;
using no = std::false_type;
template <typename U>
static auto test(int) -> decltype(std::to_string(U{}), yes());
template <typename>
static no test(...);
public:
static constexpr bool value =
std::is_same<decltype(test<Type>(0)), yes>::value;
};
} // namespace internal
class OStringStream
{
public:
OStringStream() = default;
void reserve(size_t size)
{
buffer_.reserve(size);
}
template <typename T>
std::enable_if_t<!internal::CanConvertToString<T>::value, OStringStream&>
operator<<(T&& value)
{
std::stringstream ss;
ss << std::forward<T>(value);
buffer_.append(ss.str());
return *this;
}
template <typename T>
std::enable_if_t<internal::CanConvertToString<T>::value, OStringStream&>
operator<<(T&& value)
{
buffer_.append(std::to_string(std::forward<T>(value)));
return *this;
}
template <int N>
OStringStream& operator<<(const char (&buf)[N])
{
buffer_.append(buf, N - 1);
return *this;
}
OStringStream& operator<<(const string_view& str)
{
buffer_.append(str.data(), str.length());
return *this;
}
OStringStream& operator<<(string_view&& str)
{
buffer_.append(str.data(), str.length());
return *this;
}
OStringStream& operator<<(const std::string& str)
{
buffer_.append(str);
return *this;
}
OStringStream& operator<<(std::string&& str)
{
buffer_.append(std::move(str));
return *this;
}
OStringStream& operator<<(const double& d)
{
std::stringstream ss;
ss << d;
buffer_.append(ss.str());
return *this;
}
OStringStream& operator<<(const float& f)
{
std::stringstream ss;
ss << f;
buffer_.append(ss.str());
return *this;
}
OStringStream& operator<<(double&& d)
{
std::stringstream ss;
ss << d;
buffer_.append(ss.str());
return *this;
}
OStringStream& operator<<(float&& f)
{
std::stringstream ss;
ss << f;
buffer_.append(ss.str());
return *this;
}
std::string& str()
{
return buffer_;
}
const std::string& str() const
{
return buffer_;
}
private:
std::string buffer_;
};
} // namespace drogon

View File

@ -37,8 +37,6 @@ static HttpResponsePtr genHttpResponse(std::string viewName,
if (templ)
{
auto res = HttpResponse::newHttpResponse();
res->setStatusCode(k200OK);
res->setContentTypeCode(CT_TEXT_HTML);
res->setBody(templ->genText(data));
return res;
}
@ -255,7 +253,7 @@ void HttpResponseImpl::makeHeaderString(
{
if (closeConnection_)
{
if(version_ == Version::kHttp11)
if (version_ == Version::kHttp11)
{
headerStringPtr->append("Connection: close\r\n");
}

View File

@ -3,13 +3,15 @@ add_executable(drobject_unittest DrObjectUnittest.cpp)
add_executable(gzip_unittest GzipUnittest.cpp)
add_executable(md5_unittest MD5Unittest.cpp ../lib/src/ssl_funcs/Md5.cc)
add_executable(sha1_unittest SHA1Unittest.cpp ../lib/src/ssl_funcs/Sha1.cc)
add_executable(ostringstream_unittest OStringStreamUnitttest.cpp)
set(UNITTEST_TARGETS
msgbuffer_unittest
drobject_unittest
gzip_unittest
md5_unittest
sha1_unittest)
sha1_unittest
ostringstream_unittest)
set_property(TARGET ${UNITTEST_TARGETS}
PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD})

View File

@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <drogon/utils/OStringStream.h>
#include <string>
#include <iostream>
TEST(OStringStreamTest, interger)
{
drogon::OStringStream ss;
ss << 12;
ss << 345L;
EXPECT_EQ(ss.str(), "12345");
}
TEST(OStringStreamTest, float_number)
{
drogon::OStringStream ss;
ss << 3.14f;
ss << 3.1416;
EXPECT_EQ(ss.str(), "3.143.1416");
}
TEST(OStringStreamTest, literal_string)
{
drogon::OStringStream ss;
ss << "hello";
ss << " world";
EXPECT_EQ(ss.str(), "hello world");
}
TEST(OStringStreamTest, string_view)
{
drogon::OStringStream ss;
ss << drogon::string_view("hello");
ss << drogon::string_view(" world");
EXPECT_EQ(ss.str(), "hello world");
}
TEST(OStringStreamTest, std_string)
{
drogon::OStringStream ss;
ss << std::string("hello");
ss << std::string(" world");
EXPECT_EQ(ss.str(), "hello world");
}
TEST(OStringStreamTest, mix)
{
drogon::OStringStream ss;
ss << std::string("hello");
ss << drogon::string_view(" world");
ss << "!";
ss << 123;
ss << 3.14f;
EXPECT_EQ(ss.str(), "hello world!1233.14");
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}