mirror of
https://github.com/oatpp/oatpp.git
synced 2025-04-18 19:00:23 +08:00
commit
05405fff86
299
changelog/1.3.0.md
Normal file
299
changelog/1.3.0.md
Normal file
@ -0,0 +1,299 @@
|
||||
# Oat++ 1.3.0
|
||||
|
||||
Previous release - [1.2.5](1.2.5.md)
|
||||
|
||||
Feel free to ask questions - [Chat on Gitter!](https://gitter.im/oatpp-framework/Lobby)
|
||||
|
||||
Contents:
|
||||
|
||||
- [The New oatpp::String](#the-new-oatppstring)
|
||||
- [ConnectionPool::get() Timeout](#connectionpoolget-timeout)
|
||||
- [JSON Serializer Escape Flags](#json-serializer-escape-flags)
|
||||
- [ConnectionMonitor](#connectionmonitor)
|
||||
- [Request Data Bundle](#request-data-bundle)
|
||||
- [ConnectionProviderSwitch](#connectionproviderswitch)
|
||||
- [Proper Server Stoppage](#proper-server-stoppage)
|
||||
- [Response::getBody()](#responsegetbody)
|
||||
- [data::stream::FIFOStream](#datastreamfifostream)
|
||||
- [data::stream::BufferedInputStream](#datastreambufferedinputstream)
|
||||
- [oatpp::parser::json::mapping::Serializer::Config::alwaysIncludeRequired](#oatppparserjsonmappingserializerconfigalwaysincluderequired)
|
||||
|
||||
|
||||
## The New oatpp::String
|
||||
|
||||
Now it's much easier to use `oatpp::String` since `oatpp::String` is now wrapper over `std::string`
|
||||
|
||||
```cpp
|
||||
{
|
||||
std::string s1 = Hello;
|
||||
oatpp::String s2 = s1;
|
||||
}
|
||||
|
||||
{
|
||||
oatpp::String s1 = "Hello";
|
||||
std::string s2 = *s1; // *s1 returns a refernce to the internal std::string object
|
||||
}
|
||||
|
||||
{
|
||||
oatpp::String s1 = "Hello";
|
||||
std::string s2 = s1; // s1 is used a l-value with a typecast operator
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
oatpp::String s1 = "Hello";
|
||||
bool b = s1 == "Hello"; // compare s1 with const char*
|
||||
assert(b);
|
||||
}
|
||||
|
||||
{
|
||||
oatpp::String s1 = "Hello";
|
||||
std::stringg s2 = "Hello";
|
||||
bool b = s1 == s2; // compare s1 with std::string
|
||||
assert(b);
|
||||
}
|
||||
|
||||
{
|
||||
oatpp::String s1 = "Hello";
|
||||
std::string s2 = "World";
|
||||
|
||||
oatpp::String s3 = s1 + " " + s2; // concat oatpp::String with const char* and std::string directly
|
||||
|
||||
OATPP_LOGD("TEST", "str='%s'", s3->c_str()); // prints 'Hello World'
|
||||
}
|
||||
```
|
||||
|
||||
## ConnectionPool::get() Timeout
|
||||
|
||||
[#408](https://github.com/oatpp/oatpp/issues/408)
|
||||
|
||||
```cpp
|
||||
{
|
||||
|
||||
auto connectionProvider = oatpp::network::tcp::client::ConnectionProvider::createShared({"httpbin.org", 80});
|
||||
|
||||
auto pool = oatpp::network::ClientConnectionPool::createShared(connectionProvider,
|
||||
1,
|
||||
std::chrono::seconds(10),
|
||||
std::chrono::seconds(5));
|
||||
|
||||
OATPP_LOGD("TEST", "start")
|
||||
|
||||
auto c1 = pool->get(); //<--- this one will succeed
|
||||
OATPP_LOGD("TEST", "c1=%llu", c1.get())
|
||||
|
||||
auto c2 = pool->get(); //<--- this one will fail in 5 sec. Since Max-Resources is 1, Pool timeout is 5 sec. And c1 is not freed.
|
||||
OATPP_LOGD("TEST", "c2=%llu", c2.get())
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
D |2021-08-04 01:32:56 1628029976986744| TEST:start
|
||||
D |2021-08-04 01:32:57 1628029977126940| TEST:c1=140716915331208
|
||||
D |2021-08-04 01:33:02 1628029982128324| TEST:c2=0
|
||||
```
|
||||
|
||||
## JSON Serializer Escape Flags
|
||||
|
||||
[#381](https://github.com/oatpp/oatpp/issues/381)
|
||||
|
||||
Now you can control if solidus is escaped or not.
|
||||
|
||||
### Default Behavior
|
||||
|
||||
```cpp
|
||||
oatpp::parser::json::mapping::ObjectMapper mapper;
|
||||
// mapper.getSerializer()->getConfig()->escapeFlags = 0; // by default FLAG_ESCAPE_SOLIDUS is ON
|
||||
auto res = mapper.writeToString(oatpp::String("https://oatpp.io/"));
|
||||
OATPP_LOGD("TEST", "res='%s'", res->c_str());
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
res='"https:\/\/oatpp.io\/"' # by default, solidus is escaped
|
||||
```
|
||||
|
||||
### Clear Escape Flags
|
||||
|
||||
```cpp
|
||||
oatpp::parser::json::mapping::ObjectMapper mapper;
|
||||
mapper.getSerializer()->getConfig()->escapeFlags = 0;
|
||||
auto res = mapper.writeToString(oatpp::String("https://oatpp.io/"));
|
||||
OATPP_LOGD("TEST", "res='%s'", res->c_str());
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
res='"https://oatpp.io/"' # solidus isn't escaped
|
||||
```
|
||||
|
||||
## ConnectionMonitor
|
||||
|
||||
`oatpp::network::monitor::ConnectionMonitor` is a middleman who's able to monitor provided connections and close those ones that not satisfy selected rules.
|
||||
|
||||
```cpp
|
||||
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] {
|
||||
|
||||
auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", 8000, oatpp::network::Address::IP_4});
|
||||
auto monitor = std::make_shared<oatpp::network::monitor::ConnectionMonitor>(connectionProvider);
|
||||
|
||||
/* close all connections that stay opened for more than 120 seconds */
|
||||
monitor->addMetricsChecker(
|
||||
std::make_shared<oatpp::network::monitor::ConnectionMaxAgeChecker>(
|
||||
std::chrono::seconds(120)
|
||||
)
|
||||
);
|
||||
|
||||
/* close all connections that have had no successful reads and writes for longer than 5 seconds */
|
||||
monitor->addMetricsChecker(
|
||||
std::make_shared<oatpp::network::monitor::ConnectionInactivityChecker>(
|
||||
std::chrono::seconds(5),
|
||||
std::chrono::seconds(5),
|
||||
)
|
||||
);
|
||||
|
||||
return monitor;
|
||||
|
||||
}());
|
||||
```
|
||||
|
||||
**Note:** `ConnectionMonitor` also works with `ClientConnectionProvider` as well.
|
||||
|
||||
## Request Data Bundle
|
||||
|
||||
Now there is a data bundle associated with the Request and the Response which makes it easy to pass data through middleware interceptors and endpoints.
|
||||
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
class MyAuthInterceptor : public oatpp::web::server::interceptor::RequestInterceptor {
|
||||
public:
|
||||
|
||||
std::shared_ptr<OutgoingResponse> intercept(const std::shared_ptr<IncomingRequest>& request) override {
|
||||
|
||||
/* authorize request and get auth data */
|
||||
oatpp::Object<AuthDto> authData = authorize(request);
|
||||
|
||||
if(!authData) {
|
||||
return OutgoingResponse::createShared(Status::CODE_401, nullptr);
|
||||
}
|
||||
|
||||
/* put auth data to bundle for later use at an endpoint */
|
||||
request->putBundleData("auth", authData);
|
||||
|
||||
return nullptr; // continue processing
|
||||
}
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
ENDPOINT("GET", "videos/{videoId}", getVideoById,
|
||||
PATH(String, videoId),
|
||||
BUNDLE(oatpp::Object<AuthDto>, authData, "auth"))
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## ConnectionProviderSwitch
|
||||
|
||||
[#483](https://github.com/oatpp/oatpp/issues/483)
|
||||
|
||||
`oatpp::network::ConnectionProviderSwitch` can be used to change connection providers on the go, ex.: when you want to reload an SSL certificate without stopping the server.
|
||||
|
||||
```cpp
|
||||
/* create server connection provider component */
|
||||
/* use ConnectionProviderSwitch instead of a regular ServerConnectionProvider */
|
||||
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionProviderSwitch>, serverConnectionProvider)([this] {
|
||||
/* create SSL provider */
|
||||
auto sslProvider = oatpp::libressl::server::ConnectionProvider::createShared(...);
|
||||
|
||||
/* create oatpp::network::ConnectionProviderSwitch*/
|
||||
return std::make_shared<oatpp::network::ConnectionProviderSwitch>(sslProvider /* current provider */);
|
||||
}());
|
||||
|
||||
|
||||
...
|
||||
|
||||
void reloadCert() {
|
||||
|
||||
/* get server connection provider component */
|
||||
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionProviderSwitch>, providerSwitch);
|
||||
|
||||
/* create new SSL provider with new cert */
|
||||
auto sslProvider = oatpp::libressl::server::ConnectionProvider::createShared(...);
|
||||
|
||||
/* set new provider */
|
||||
providerSwitch->resetProvider(sslProvider);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Proper Server Stoppage
|
||||
|
||||
Fix to [#476](https://github.com/oatpp/oatpp/issues/476), [#269](https://github.com/oatpp/oatpp/issues/269)
|
||||
|
||||
Now call to `HttpConnectionHandler::stop()`, `AsyncHttpConnectionHandler::stop()` will shutdown all opened connections and will wait until all request handlers exit.
|
||||
|
||||
## Response::getBody()
|
||||
|
||||
`oatpp::web::protocol::http::outgoing::Response` has a new method `getBody()` to retreive the body of the response.
|
||||
This is handy for response interceptors.
|
||||
|
||||
|
||||
## data::stream::FIFOStream
|
||||
|
||||
The new `FIFOStream` stream is a buffered
|
||||
[`InputStream`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#inputstream) with an
|
||||
[`WriteCallback`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#writecallback).
|
||||
Check the corresponding documentation on how to use these interfaces.
|
||||
|
||||
Instead of using a static buffer like `BufferInputStream` it is build upon `data::buffer::FIFOBuffer` and is able to
|
||||
dynamically grow when data is written to it that would surpass its capacity.
|
||||
It is especially useful if you need to buffer data from a stream upfront or have multiple data sources that should be
|
||||
buffered in a single stream.
|
||||
However, it is not synchronized, so be careful when using `FIFOStream` in a multithreaded manner.
|
||||
You need to implement your own locking.
|
||||
|
||||
|
||||
## data::stream::BufferedInputStream
|
||||
|
||||
`FIFOStream` also introduced a new interface
|
||||
[`BufferedInputStream`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#bufferedinputstream) which unifies
|
||||
the bufferd-stream-interface all existing buffered streams (`InputStreamBufferedProxy`, `BufferInputStream`,
|
||||
`FIFOStream`) to allow for generalisation.
|
||||
|
||||
## oatpp::parser::json::mapping::Serializer::Config::alwaysIncludeRequired
|
||||
|
||||
If `oatpp::parser::json::mapping::Serializer::Config::includeNullFields == false` there might still be the requirement
|
||||
to include some fields even if they are `nullptr`, because they are required by the deserializing end.
|
||||
|
||||
Consider the following DTO and endpoint-snippet.
|
||||
```c++
|
||||
class StatusDto : public oatpp::DTO {
|
||||
DTO_INIT(StatusDto, DTO)
|
||||
DTO_FIELD_INFO(status) {
|
||||
info->required = true;
|
||||
}
|
||||
DTO_FIELD(String, status);
|
||||
DTO_FIELD(Int32, code);
|
||||
DTO_FIELD(String, message);
|
||||
};
|
||||
|
||||
// endpoint code:
|
||||
ENDPOINT("GET", "/status", status) {
|
||||
auto dto = StatusDto::createShared();
|
||||
dto->code = 200;
|
||||
return createDtoResponse(Status::CODE_200, dto);
|
||||
}
|
||||
```
|
||||
With a serializer with its config set to `Serializer::Config::includeNullFields = false`, the snippet would just yield `{"code":200}`.
|
||||
|
||||
However, `status` is a required field.
|
||||
Now, one can set `Serializer::Config::alwaysIncludeRequired = true`.
|
||||
With `alwaysIncludeRequired == true`, the same snippet would yield `{"status":null,"code":200}`, even with `includeNullFields == false`.
|
@ -11,6 +11,8 @@ add_library(oatpp
|
||||
oatpp/codegen/api_controller/base_undef.hpp
|
||||
oatpp/codegen/api_controller/auth_define.hpp
|
||||
oatpp/codegen/api_controller/auth_undef.hpp
|
||||
oatpp/codegen/api_controller/bundle_define.hpp
|
||||
oatpp/codegen/api_controller/bundle_undef.hpp
|
||||
oatpp/codegen/api_controller/cors_define.hpp
|
||||
oatpp/codegen/api_controller/cors_undef.hpp
|
||||
oatpp/codegen/ApiController_define.hpp
|
||||
@ -55,8 +57,6 @@ add_library(oatpp
|
||||
oatpp/core/base/Environment.cpp
|
||||
oatpp/core/base/Environment.hpp
|
||||
oatpp/core/base/ObjectHandle.hpp
|
||||
oatpp/core/base/StrBuffer.cpp
|
||||
oatpp/core/base/StrBuffer.hpp
|
||||
oatpp/core/base/memory/Allocator.cpp
|
||||
oatpp/core/base/memory/Allocator.hpp
|
||||
oatpp/core/base/memory/MemoryPool.cpp
|
||||
@ -64,8 +64,6 @@ add_library(oatpp
|
||||
oatpp/core/base/memory/ObjectPool.cpp
|
||||
oatpp/core/base/memory/ObjectPool.hpp
|
||||
oatpp/core/collection/FastQueue.hpp
|
||||
oatpp/core/collection/LinkedList.hpp
|
||||
oatpp/core/collection/ListMap.hpp
|
||||
oatpp/core/concurrency/SpinLock.cpp
|
||||
oatpp/core/concurrency/SpinLock.hpp
|
||||
oatpp/core/concurrency/Thread.cpp
|
||||
@ -111,12 +109,16 @@ add_library(oatpp
|
||||
oatpp/core/data/stream/BufferStream.hpp
|
||||
oatpp/core/data/stream/ChunkedBuffer.cpp
|
||||
oatpp/core/data/stream/ChunkedBuffer.hpp
|
||||
oatpp/core/data/stream/FIFOStream.cpp
|
||||
oatpp/core/data/stream/FIFOStream.hpp
|
||||
oatpp/core/data/stream/FileStream.cpp
|
||||
oatpp/core/data/stream/FileStream.hpp
|
||||
oatpp/core/data/stream/Stream.cpp
|
||||
oatpp/core/data/stream/Stream.hpp
|
||||
oatpp/core/data/stream/StreamBufferedProxy.cpp
|
||||
oatpp/core/data/stream/StreamBufferedProxy.hpp
|
||||
oatpp/core/data/Bundle.cpp
|
||||
oatpp/core/data/Bundle.hpp
|
||||
oatpp/core/macro/basic.hpp
|
||||
oatpp/core/macro/codegen.hpp
|
||||
oatpp/core/macro/component.hpp
|
||||
@ -124,6 +126,7 @@ add_library(oatpp
|
||||
oatpp/core/parser/Caret.hpp
|
||||
oatpp/core/parser/ParsingError.cpp
|
||||
oatpp/core/parser/ParsingError.hpp
|
||||
oatpp/core/provider/Invalidator.hpp
|
||||
oatpp/core/provider/Pool.hpp
|
||||
oatpp/core/provider/Provider.hpp
|
||||
oatpp/core/utils/Binary.cpp
|
||||
@ -132,12 +135,22 @@ add_library(oatpp
|
||||
oatpp/core/utils/ConversionUtils.hpp
|
||||
oatpp/core/utils/Random.cpp
|
||||
oatpp/core/utils/Random.hpp
|
||||
oatpp/core/utils/String.cpp
|
||||
oatpp/core/utils/String.hpp
|
||||
oatpp/encoding/Base64.cpp
|
||||
oatpp/encoding/Base64.hpp
|
||||
oatpp/encoding/Hex.cpp
|
||||
oatpp/encoding/Hex.hpp
|
||||
oatpp/encoding/Unicode.cpp
|
||||
oatpp/encoding/Unicode.hpp
|
||||
oatpp/network/monitor/ConnectionInactivityChecker.cpp
|
||||
oatpp/network/monitor/ConnectionInactivityChecker.hpp
|
||||
oatpp/network/monitor/ConnectionMaxAgeChecker.cpp
|
||||
oatpp/network/monitor/ConnectionMaxAgeChecker.hpp
|
||||
oatpp/network/monitor/ConnectionMonitor.cpp
|
||||
oatpp/network/monitor/ConnectionMonitor.hpp
|
||||
oatpp/network/monitor/MetricsChecker.hpp
|
||||
oatpp/network/monitor/StatCollector.hpp
|
||||
oatpp/network/tcp/client/ConnectionProvider.cpp
|
||||
oatpp/network/tcp/client/ConnectionProvider.hpp
|
||||
oatpp/network/tcp/server/ConnectionProvider.cpp
|
||||
@ -161,6 +174,8 @@ add_library(oatpp
|
||||
oatpp/network/ConnectionPool.hpp
|
||||
oatpp/network/ConnectionProvider.cpp
|
||||
oatpp/network/ConnectionProvider.hpp
|
||||
oatpp/network/ConnectionProviderSwitch.cpp
|
||||
oatpp/network/ConnectionProviderSwitch.hpp
|
||||
oatpp/network/Server.cpp
|
||||
oatpp/network/Server.hpp
|
||||
oatpp/network/Url.cpp
|
||||
@ -277,6 +292,9 @@ set_target_properties(oatpp PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
if (MSVC)
|
||||
target_compile_options(oatpp PRIVATE /permissive-)
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||
|
||||
@ -321,6 +339,9 @@ set_target_properties(oatpp-test PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
if (MSVC)
|
||||
target_compile_options(oatpp-test PRIVATE /permissive-)
|
||||
endif()
|
||||
|
||||
target_link_libraries(oatpp-test PUBLIC oatpp)
|
||||
|
||||
|
@ -47,4 +47,5 @@
|
||||
|
||||
#include "./api_controller/base_define.hpp"
|
||||
#include "./api_controller/auth_define.hpp"
|
||||
#include "./api_controller/bundle_define.hpp"
|
||||
#include "./api_controller/cors_define.hpp"
|
||||
|
@ -44,4 +44,5 @@
|
||||
|
||||
#include "./api_controller/base_undef.hpp"
|
||||
#include "./api_controller/auth_undef.hpp"
|
||||
#include "./api_controller/bundle_undef.hpp"
|
||||
#include "./api_controller/cors_undef.hpp"
|
||||
|
40
src/oatpp/codegen/api_controller/bundle_define.hpp
Normal file
40
src/oatpp/codegen/api_controller/bundle_define.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Benedikt-Alexander Mokroß <bam@icognize.de>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define BUNDLE(TYPE, ...) \
|
||||
OATPP_MACRO_API_CONTROLLER_PARAM(OATPP_MACRO_API_CONTROLLER_BUNDLE, OATPP_MACRO_API_CONTROLLER_BUNDLE_INFO, TYPE, (__VA_ARGS__))
|
||||
|
||||
// BUNDLE MACRO // ------------------------------------------------------
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_BUNDLE_1(TYPE, NAME) \
|
||||
TYPE NAME = __request->getBundleData<TYPE>(#NAME);
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_BUNDLE_2(TYPE, NAME, QUALIFIER) \
|
||||
TYPE NAME = __request->getBundleData<TYPE>(QUALIFIER);
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_BUNDLE(TYPE, PARAM_LIST) \
|
||||
OATPP_MACRO_API_CONTROLLER_MACRO_SELECTOR(OATPP_MACRO_API_CONTROLLER_BUNDLE_, TYPE, OATPP_MACRO_UNFOLD_VA_ARGS PARAM_LIST)
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_BUNDLE_INFO(TYPE, PARAM_LIST)
|
32
src/oatpp/codegen/api_controller/bundle_undef.hpp
Normal file
32
src/oatpp/codegen/api_controller/bundle_undef.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Benedikt-Alexander Mokroß <bam@icognize.de>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#undef BUNDLE
|
||||
|
||||
#undef OATPP_MACRO_API_CONTROLLER_BUNDLE_1
|
||||
#undef OATPP_MACRO_API_CONTROLLER_BUNDLE_2
|
||||
#undef OATPP_MACRO_API_CONTROLLER_BUNDLE
|
||||
|
||||
#undef OATPP_MACRO_API_CONTROLLER_BUNDLE_INFO
|
@ -47,8 +47,6 @@ private: \
|
||||
return ↦ \
|
||||
} \
|
||||
public: \
|
||||
\
|
||||
TYPE_NAME() = default; \
|
||||
\
|
||||
template<typename ... Args> \
|
||||
static Wrapper createShared(Args... args){ \
|
||||
|
@ -52,7 +52,7 @@ namespace oatpp {
|
||||
|
||||
/**
|
||||
* Mapping-Enabled String type. &id:oatpp::data::mapping::type::String; <br>
|
||||
* For `oatpp::String` methods see &id:oatpp::base::StrBuffer;
|
||||
* For `oatpp::String` methods see `std::string`
|
||||
*/
|
||||
typedef oatpp::data::mapping::type::String String;
|
||||
|
||||
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -65,6 +66,13 @@ Action Action::createWaitListAction(CoroutineWaitList* waitList) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Action Action::createWaitListActionWithTimeout(CoroutineWaitList* waitList, const std::chrono::steady_clock::time_point& timeout) {
|
||||
Action result(TYPE_WAIT_LIST_WITH_TIMEOUT);
|
||||
result.m_data.waitListWithTimeout.waitList = waitList;
|
||||
result.m_data.waitListWithTimeout.timeoutTimeSinceEpochMS = std::chrono::duration_cast<std::chrono::milliseconds>(timeout.time_since_epoch()).count();
|
||||
return result;
|
||||
}
|
||||
|
||||
Action::Action()
|
||||
: m_type(TYPE_NONE)
|
||||
{}
|
||||
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -113,6 +114,11 @@ public:
|
||||
*/
|
||||
static constexpr const v_int32 TYPE_WAIT_LIST = 9;
|
||||
|
||||
/**
|
||||
* Indicate that coroutine should be put on a wait-list provided with a timeout.
|
||||
*/
|
||||
static constexpr const v_int32 TYPE_WAIT_LIST_WITH_TIMEOUT = 10;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -174,6 +180,11 @@ private:
|
||||
IOEventType ioEventType;
|
||||
};
|
||||
|
||||
struct WaitListWithTimeout {
|
||||
CoroutineWaitList* waitList;
|
||||
v_int64 timeoutTimeSinceEpochMS;
|
||||
};
|
||||
|
||||
private:
|
||||
union Data {
|
||||
FunctionPtr fptr;
|
||||
@ -182,6 +193,7 @@ private:
|
||||
IOData ioData;
|
||||
v_int64 timePointMicroseconds;
|
||||
CoroutineWaitList* waitList;
|
||||
WaitListWithTimeout waitListWithTimeout;
|
||||
};
|
||||
private:
|
||||
mutable v_int32 m_type;
|
||||
@ -243,6 +255,14 @@ public:
|
||||
*/
|
||||
static Action createWaitListAction(CoroutineWaitList* waitList);
|
||||
|
||||
/**
|
||||
* Create TYPE_WAIT_LIST_WITH_TIMEOUT Action.
|
||||
* @param waitList - wait-list to put coroutine on.
|
||||
* @param timeout - latest time point at which the coroutine should be continued.
|
||||
* @return - Action.
|
||||
*/
|
||||
static Action createWaitListActionWithTimeout(CoroutineWaitList* waitList, const std::chrono::steady_clock::time_point& timeout);
|
||||
|
||||
/**
|
||||
* Constructor. Create start-coroutine Action.
|
||||
* @param coroutine - pointer to &l:AbstractCoroutine;.
|
||||
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -25,18 +26,63 @@
|
||||
#include "CoroutineWaitList.hpp"
|
||||
|
||||
#include "./Processor.hpp"
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
namespace oatpp { namespace async {
|
||||
|
||||
|
||||
CoroutineWaitList::CoroutineWaitList(CoroutineWaitList&& other) {
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{other.m_lock};
|
||||
m_list = std::move(other.m_list);
|
||||
}
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{other.m_timeoutsLock};
|
||||
m_coroutinesWithTimeout = std::move(other.m_coroutinesWithTimeout);
|
||||
|
||||
m_timeoutCheckingProcessors = std::move(other.m_timeoutCheckingProcessors);
|
||||
for (const std::pair<Processor*, v_int64>& entry : m_timeoutCheckingProcessors) {
|
||||
Processor* processor = entry.first;
|
||||
processor->removeCoroutineWaitListWithTimeouts(std::addressof(other));
|
||||
processor->addCoroutineWaitListWithTimeouts(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CoroutineWaitList::~CoroutineWaitList() {
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
void CoroutineWaitList::checkCoroutinesForTimeouts() {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> listLock{m_lock};
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{m_timeoutsLock};
|
||||
const auto currentTimeSinceEpochMS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
const auto newEndIt = std::remove_if(std::begin(m_coroutinesWithTimeout), std::end(m_coroutinesWithTimeout), [&](const std::pair<CoroutineHandle*, v_int64>& entry) {
|
||||
return currentTimeSinceEpochMS > entry.second;
|
||||
});
|
||||
|
||||
for (CoroutineHandle* curr = m_list.first, *prev = nullptr; !m_list.empty() && m_list.last->_ref != curr; curr = curr->_ref) {
|
||||
const bool removeFromWaitList = std::any_of(newEndIt, std::end(m_coroutinesWithTimeout), [=](const std::pair<CoroutineHandle*, v_int64>& entry) {
|
||||
return entry.first == curr;
|
||||
});
|
||||
if (!removeFromWaitList) {
|
||||
prev = curr;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_list.cutEntry(curr, prev);
|
||||
|
||||
if (--m_timeoutCheckingProcessors[curr->_PP] <= 0) {
|
||||
curr->_PP->removeCoroutineWaitListWithTimeouts(this);
|
||||
m_timeoutCheckingProcessors.erase(curr->_PP);
|
||||
}
|
||||
curr->_PP->pushOneTask(curr);
|
||||
}
|
||||
|
||||
m_coroutinesWithTimeout.erase(newEndIt, std::end(m_coroutinesWithTimeout));
|
||||
}
|
||||
|
||||
void CoroutineWaitList::setListener(Listener* listener) {
|
||||
m_listener = listener;
|
||||
}
|
||||
@ -51,6 +97,17 @@ void CoroutineWaitList::pushFront(CoroutineHandle* coroutine) {
|
||||
}
|
||||
}
|
||||
|
||||
void CoroutineWaitList::pushFront(CoroutineHandle* coroutine, v_int64 timeoutTimeSinceEpochMS) {
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{m_timeoutsLock};
|
||||
m_coroutinesWithTimeout.emplace_back(coroutine, timeoutTimeSinceEpochMS);
|
||||
if (++m_timeoutCheckingProcessors[coroutine->_PP] == 1) {
|
||||
coroutine->_PP->addCoroutineWaitListWithTimeouts(this);
|
||||
}
|
||||
}
|
||||
pushFront(coroutine);
|
||||
}
|
||||
|
||||
void CoroutineWaitList::pushBack(CoroutineHandle* coroutine) {
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock(m_lock);
|
||||
@ -61,21 +118,68 @@ void CoroutineWaitList::pushBack(CoroutineHandle* coroutine) {
|
||||
}
|
||||
}
|
||||
|
||||
void CoroutineWaitList::pushBack(CoroutineHandle* coroutine, v_int64 timeoutTimeSinceEpochMS) {
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{m_timeoutsLock};
|
||||
m_coroutinesWithTimeout.emplace_back(coroutine, timeoutTimeSinceEpochMS);
|
||||
if (++m_timeoutCheckingProcessors[coroutine->_PP] == 1) {
|
||||
coroutine->_PP->addCoroutineWaitListWithTimeouts(this);
|
||||
}
|
||||
}
|
||||
pushBack(coroutine);
|
||||
}
|
||||
|
||||
void CoroutineWaitList::notifyFirst() {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock(m_lock);
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{m_lock};
|
||||
if(m_list.first) {
|
||||
auto coroutine = m_list.popFront();
|
||||
coroutine->_PP->pushOneTask(coroutine);
|
||||
removeFirstCoroutine();
|
||||
}
|
||||
}
|
||||
|
||||
void CoroutineWaitList::notifyAll() {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock(m_lock);
|
||||
while (!m_list.empty()) {
|
||||
auto curr = m_list.popFront();
|
||||
curr->_PP->pushOneTask(curr);
|
||||
}
|
||||
while (!m_list.empty()) {
|
||||
removeFirstCoroutine();
|
||||
}
|
||||
}
|
||||
|
||||
void CoroutineWaitList::removeFirstCoroutine() {
|
||||
auto coroutine = m_list.popFront();
|
||||
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock{m_timeoutsLock};
|
||||
if (--m_timeoutCheckingProcessors[coroutine->_PP] <= 0) {
|
||||
coroutine->_PP->removeCoroutineWaitListWithTimeouts(this);
|
||||
m_timeoutCheckingProcessors.erase(coroutine->_PP);
|
||||
}
|
||||
}
|
||||
|
||||
coroutine->_PP->pushOneTask(coroutine);
|
||||
}
|
||||
|
||||
CoroutineWaitList& CoroutineWaitList::operator=(CoroutineWaitList&& other) {
|
||||
if (this == std::addressof(other)) return *this;
|
||||
|
||||
notifyAll();
|
||||
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> otherLock{other.m_lock};
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> myLock{m_lock};
|
||||
m_list = std::move(other.m_list);
|
||||
}
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> otherLock{other.m_timeoutsLock};
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> myLock{m_timeoutsLock};
|
||||
m_coroutinesWithTimeout = std::move(other.m_coroutinesWithTimeout);
|
||||
|
||||
m_timeoutCheckingProcessors = std::move(other.m_timeoutCheckingProcessors);
|
||||
for (const std::pair<Processor*, v_int64>& entry : m_timeoutCheckingProcessors) {
|
||||
Processor* processor = entry.first;
|
||||
processor->removeCoroutineWaitListWithTimeouts(std::addressof(other));
|
||||
processor->addCoroutineWaitListWithTimeouts(this);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}}
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,7 +30,10 @@
|
||||
#include "oatpp/core/collection/FastQueue.hpp"
|
||||
|
||||
#include "oatpp/core/concurrency/SpinLock.hpp"
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
namespace oatpp { namespace async {
|
||||
|
||||
@ -59,6 +63,16 @@ private:
|
||||
oatpp::collection::FastQueue<CoroutineHandle> m_list;
|
||||
oatpp::concurrency::SpinLock m_lock;
|
||||
Listener* m_listener = nullptr;
|
||||
|
||||
std::map<Processor*, v_int64> m_timeoutCheckingProcessors;
|
||||
std::vector<std::pair<CoroutineHandle*, v_int64>> m_coroutinesWithTimeout;
|
||||
oatpp::concurrency::SpinLock m_timeoutsLock;
|
||||
|
||||
private:
|
||||
void checkCoroutinesForTimeouts();
|
||||
|
||||
void removeFirstCoroutine();
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Put coroutine on wait-list.
|
||||
@ -67,12 +81,28 @@ protected:
|
||||
*/
|
||||
void pushFront(CoroutineHandle* coroutine);
|
||||
|
||||
/*
|
||||
* Put coroutine on wait-list with timeout.
|
||||
* This method should be called by Coroutine Processor only.
|
||||
* @param coroutine
|
||||
* @param timeoutTimeSinceEpochMS
|
||||
*/
|
||||
void pushFront(CoroutineHandle* coroutine, v_int64 timeoutTimeSinceEpochMS);
|
||||
|
||||
/*
|
||||
* Put coroutine on wait-list.
|
||||
* This method should be called by Coroutine Processor only.
|
||||
* @param coroutine
|
||||
*/
|
||||
void pushBack(CoroutineHandle* coroutine);
|
||||
|
||||
/*
|
||||
* Put coroutine on wait-list with timeout.
|
||||
* This method should be called by Coroutine Processor only.
|
||||
* @param coroutine
|
||||
* @param timeoutTimeSinceEpochMS
|
||||
*/
|
||||
void pushBack(CoroutineHandle* coroutine, v_int64 timeoutTimeSinceEpochMS);
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -118,12 +148,7 @@ public:
|
||||
*/
|
||||
void notifyAll();
|
||||
|
||||
CoroutineWaitList& operator=(CoroutineWaitList&& other) {
|
||||
notifyAll();
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lock(m_lock);
|
||||
m_list = std::move(other.m_list);
|
||||
return *this;
|
||||
}
|
||||
CoroutineWaitList& operator=(CoroutineWaitList&& other);
|
||||
|
||||
};
|
||||
|
||||
|
@ -31,8 +31,6 @@
|
||||
#include "oatpp/core/concurrency/SpinLock.hpp"
|
||||
#include "oatpp/core/concurrency/Thread.hpp"
|
||||
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,6 +29,38 @@
|
||||
|
||||
namespace oatpp { namespace async {
|
||||
|
||||
void Processor::checkCoroutinesForTimeouts() {
|
||||
while (m_running) {
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock{m_coroutineWaitListsWithTimeoutsMutex};
|
||||
while (m_coroutineWaitListsWithTimeouts.empty()) {
|
||||
m_coroutineWaitListsWithTimeoutsCV.wait(lock);
|
||||
if (!m_running) return;
|
||||
}
|
||||
|
||||
const auto coroutineWaitListsWithTimeouts = m_coroutineWaitListsWithTimeouts;
|
||||
for (CoroutineWaitList* waitList : coroutineWaitListsWithTimeouts) {
|
||||
waitList->checkCoroutinesForTimeouts();
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{100});
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::addCoroutineWaitListWithTimeouts(CoroutineWaitList* waitList) {
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock{m_coroutineWaitListsWithTimeoutsMutex};
|
||||
m_coroutineWaitListsWithTimeouts.insert(waitList);
|
||||
}
|
||||
m_coroutineWaitListsWithTimeoutsCV.notify_one();
|
||||
}
|
||||
|
||||
void Processor::removeCoroutineWaitListWithTimeouts(CoroutineWaitList* waitList) {
|
||||
std::lock_guard<std::recursive_mutex> lock{m_coroutineWaitListsWithTimeoutsMutex};
|
||||
m_coroutineWaitListsWithTimeouts.erase(waitList);
|
||||
}
|
||||
|
||||
void Processor::addWorker(const std::shared_ptr<worker::Worker>& worker) {
|
||||
|
||||
switch(worker->getType()) {
|
||||
@ -97,6 +130,11 @@ void Processor::addCoroutine(CoroutineHandle* coroutine) {
|
||||
action.m_data.waitList->pushBack(coroutine);
|
||||
break;
|
||||
|
||||
case Action::TYPE_WAIT_LIST_WITH_TIMEOUT:
|
||||
coroutine->_SCH_A = Action::createActionByType(Action::TYPE_NONE);
|
||||
action.m_data.waitListWithTimeout.waitList->pushBack(coroutine, action.m_data.waitListWithTimeout.timeoutTimeSinceEpochMS);
|
||||
break;
|
||||
|
||||
default:
|
||||
m_queue.pushBack(coroutine);
|
||||
|
||||
@ -209,6 +247,12 @@ bool Processor::iterate(v_int32 numIterations) {
|
||||
action.m_data.waitList->pushBack(CP);
|
||||
break;
|
||||
|
||||
case Action::TYPE_WAIT_LIST_WITH_TIMEOUT:
|
||||
CP->_SCH_A = Action::createActionByType(Action::TYPE_NONE);
|
||||
m_queue.popFront();
|
||||
action.m_data.waitListWithTimeout.waitList->pushBack(CP, action.m_data.waitListWithTimeout.timeoutTimeSinceEpochMS);
|
||||
break;
|
||||
|
||||
default:
|
||||
m_queue.round();
|
||||
}
|
||||
@ -230,6 +274,9 @@ void Processor::stop() {
|
||||
m_running = false;
|
||||
}
|
||||
m_taskCondition.notify_one();
|
||||
|
||||
m_coroutineWaitListsWithTimeoutsCV.notify_one();
|
||||
m_coroutineWaitListTimeoutChecker.join();
|
||||
}
|
||||
|
||||
v_int32 Processor::getTasksCount() {
|
||||
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,12 +27,14 @@
|
||||
#define oatpp_async_Processor_hpp
|
||||
|
||||
#include "./Coroutine.hpp"
|
||||
#include "./CoroutineWaitList.hpp"
|
||||
#include "oatpp/core/collection/FastQueue.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace oatpp { namespace async {
|
||||
|
||||
@ -41,11 +44,12 @@ namespace oatpp { namespace async {
|
||||
* Do not use bare processor to run coroutines. Use &id:oatpp::async::Executor; instead;.
|
||||
*/
|
||||
class Processor {
|
||||
friend class CoroutineWaitList;
|
||||
private:
|
||||
|
||||
class TaskSubmission {
|
||||
public:
|
||||
virtual ~TaskSubmission() {};
|
||||
virtual ~TaskSubmission() = default;
|
||||
virtual CoroutineHandle* createCoroutine(Processor* processor) = 0;
|
||||
};
|
||||
|
||||
@ -108,8 +112,19 @@ private:
|
||||
|
||||
private:
|
||||
|
||||
bool m_running = true;
|
||||
std::atomic<v_int32> m_tasksCounter;
|
||||
std::atomic_bool m_running{true};
|
||||
std::atomic<v_int32> m_tasksCounter{0};
|
||||
|
||||
private:
|
||||
|
||||
std::recursive_mutex m_coroutineWaitListsWithTimeoutsMutex;
|
||||
std::condition_variable_any m_coroutineWaitListsWithTimeoutsCV;
|
||||
std::set<CoroutineWaitList*> m_coroutineWaitListsWithTimeouts;
|
||||
std::thread m_coroutineWaitListTimeoutChecker{&Processor::checkCoroutinesForTimeouts, this};
|
||||
|
||||
void checkCoroutinesForTimeouts();
|
||||
void addCoroutineWaitListWithTimeouts(CoroutineWaitList* waitList);
|
||||
void removeCoroutineWaitListWithTimeouts(CoroutineWaitList* waitList);
|
||||
|
||||
private:
|
||||
|
||||
@ -123,10 +138,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
Processor()
|
||||
: m_running(true)
|
||||
, m_tasksCounter(0)
|
||||
{}
|
||||
Processor() = default;
|
||||
|
||||
/**
|
||||
* Add dedicated co-worker to processor.
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define oatpp_async_worker_IOWorker_hpp
|
||||
|
||||
#include "./Worker.hpp"
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
#include "oatpp/core/concurrency/SpinLock.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define oatpp_async_worker_TimerWorker_hpp
|
||||
|
||||
#include "./Worker.hpp"
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
#include "oatpp/core/concurrency/SpinLock.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
|
||||
#define OATPP_VERSION "1.2.5"
|
||||
#define OATPP_VERSION "1.3.0"
|
||||
|
||||
typedef unsigned char v_char8;
|
||||
typedef v_char8 *p_char8;
|
||||
|
@ -1,388 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "StrBuffer.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace oatpp { namespace base {
|
||||
|
||||
void StrBuffer::set(const void* data, v_buff_size size, bool hasOwnData) {
|
||||
m_data = (p_char8) data;
|
||||
m_size = size;
|
||||
m_hasOwnData = hasOwnData;
|
||||
}
|
||||
|
||||
void StrBuffer::setAndCopy(const void* data, const void* originData, v_buff_size size){
|
||||
m_data = (p_char8) data;
|
||||
m_size = size;
|
||||
//m_hasOwnData = false;
|
||||
if(originData != nullptr) {
|
||||
std::memcpy(m_data, originData, size);
|
||||
}
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::allocShared(const void* data, v_buff_size size, bool copyAsOwnData) {
|
||||
if(copyAsOwnData) {
|
||||
memory::AllocationExtras extras(size + 1);
|
||||
std::shared_ptr<StrBuffer> ptr;
|
||||
if(size + 1 > getSmStringSize()) {
|
||||
ptr = memory::allocateSharedWithExtras<StrBuffer>(extras);
|
||||
} else {
|
||||
ptr = memory::customPoolAllocateSharedWithExtras<StrBuffer>(extras, getSmallStringPool());
|
||||
}
|
||||
ptr->setAndCopy(extras.extraPtr, data, size);
|
||||
return ptr;
|
||||
}
|
||||
return std::make_shared<StrBuffer>(data, size, copyAsOwnData);
|
||||
}
|
||||
|
||||
p_char8 StrBuffer::allocStrBuffer(const void* originData, v_buff_size size, bool copyAsOwnData) {
|
||||
if(copyAsOwnData) {
|
||||
p_char8 data = new v_char8[size + 1];
|
||||
data[size] = 0;
|
||||
if(originData != nullptr) {
|
||||
std::memcpy(data, originData, size);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return (p_char8) originData;
|
||||
}
|
||||
|
||||
StrBuffer::StrBuffer()
|
||||
: m_data((p_char8)"[<nullptr>]")
|
||||
, m_size(11)
|
||||
, m_hasOwnData(false)
|
||||
{}
|
||||
|
||||
StrBuffer::StrBuffer(const void* data, v_buff_size size, bool copyAsOwnData)
|
||||
: m_data(allocStrBuffer(data, size, copyAsOwnData))
|
||||
, m_size(size)
|
||||
, m_hasOwnData(copyAsOwnData)
|
||||
{}
|
||||
|
||||
StrBuffer::~StrBuffer() {
|
||||
if(m_hasOwnData) {
|
||||
delete [] m_data;
|
||||
}
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::createShared(const void* data, v_buff_size size, bool copyAsOwnData) {
|
||||
return allocShared(data, size, copyAsOwnData);
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::createShared(const char* data, bool copyAsOwnData) {
|
||||
return allocShared(data, std::strlen(data), copyAsOwnData);
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::createShared(StrBuffer* other, bool copyAsOwnData) {
|
||||
return allocShared(other->getData(), other->getSize(), copyAsOwnData);
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::createShared(v_buff_size size) {
|
||||
return allocShared(nullptr, size, true);
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::createSharedConcatenated(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
|
||||
const auto& ptr = allocShared(nullptr, size1 + size2, true);
|
||||
std::memcpy(ptr->m_data, data1, size1);
|
||||
std::memcpy(ptr->m_data + size1, data2, size2);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::loadFromFile(const char* filename) {
|
||||
std::ifstream file (filename, std::ios::in|std::ios::binary|std::ios::ate);
|
||||
if (file.is_open()) {
|
||||
auto result = createShared(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char*)result->getData(), result->getSize());
|
||||
file.close();
|
||||
return result;
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StrBuffer::saveToFile(const char* filename) {
|
||||
std::ofstream fs(filename, std::ios::out | std::ios::binary);
|
||||
fs.write((const char*)m_data, m_size);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
p_char8 StrBuffer::getData() const {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
v_buff_size StrBuffer::getSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const char* StrBuffer::c_str() const {
|
||||
return (const char*) m_data;
|
||||
}
|
||||
|
||||
std::string StrBuffer::std_str() const {
|
||||
return std::string((const char*) m_data, m_size);
|
||||
}
|
||||
|
||||
bool StrBuffer::hasOwnData() const {
|
||||
return m_hasOwnData;
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::toLowerCase() const {
|
||||
const auto& ptr = allocShared(m_data, m_size, true);
|
||||
lowerCase(ptr->m_data, ptr->m_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<StrBuffer> StrBuffer::toUpperCase() const {
|
||||
const auto& ptr = allocShared(m_data, m_size, true);
|
||||
upperCase(ptr->m_data, ptr->m_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(const void* data, v_buff_size size) const {
|
||||
if(m_size == size) {
|
||||
return equals(m_data, data, size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(const char* data) const {
|
||||
if(data == nullptr) {
|
||||
return m_data == nullptr;
|
||||
}
|
||||
if(m_size == (v_buff_size) std::strlen(data)) {
|
||||
return equals(m_data, data, m_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(StrBuffer* other) const {
|
||||
return equals((StrBuffer*)this, other);
|
||||
}
|
||||
|
||||
bool StrBuffer::startsWith(const void* data, v_buff_size size) const {
|
||||
if(m_size >= size) {
|
||||
return equals(m_data, data, size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StrBuffer::startsWith(const char* data) const {
|
||||
if(data == nullptr) return false;
|
||||
v_buff_size length = std::strlen(data);
|
||||
if(m_size >= length) {
|
||||
return equals(m_data, data, length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StrBuffer::startsWith(StrBuffer* data) const {
|
||||
if(data == nullptr) return false;
|
||||
if(m_size >= data->m_size) {
|
||||
return equals(m_data, data, data->m_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
v_buff_size StrBuffer::compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
|
||||
|
||||
if(data1 == data2) return 0;
|
||||
if(data1 == nullptr) return -1;
|
||||
if(data2 == nullptr) return 1;
|
||||
|
||||
if(size1 < size2) {
|
||||
auto res = std::memcmp(data1, data2, size1);
|
||||
if(res == 0) return -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
if(size1 > size2) {
|
||||
auto res = std::memcmp(data1, data2, size2);
|
||||
if(res == 0) return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return std::memcmp(data1, data2, size1);
|
||||
|
||||
}
|
||||
|
||||
v_buff_size StrBuffer::compareCI(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
|
||||
|
||||
if(data1 == data2) return 0;
|
||||
if(data1 == nullptr) return -1;
|
||||
if(data2 == nullptr) return 1;
|
||||
|
||||
auto d1 = (p_char8) data1;
|
||||
auto d2 = (p_char8) data2;
|
||||
|
||||
v_buff_size size = size1;
|
||||
if(size2 < size1) size = size2;
|
||||
|
||||
for(v_buff_size i = 0; i < size; i ++) {
|
||||
|
||||
v_char8 a = d1[i];
|
||||
v_char8 b = d2[i];
|
||||
|
||||
if(a >= 'A' && a <= 'Z') a |= 32;
|
||||
if(b >= 'A' && b <= 'Z') b |= 32;
|
||||
|
||||
if(a != b) {
|
||||
return (int) a - (int) b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(size1 < size2) return -1;
|
||||
if(size1 > size2) return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
v_buff_size StrBuffer::compareCI_FAST(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
|
||||
|
||||
if(data1 == data2) return 0;
|
||||
if(data1 == nullptr) return -1;
|
||||
if(data2 == nullptr) return 1;
|
||||
|
||||
auto d1 = (p_char8) data1;
|
||||
auto d2 = (p_char8) data2;
|
||||
|
||||
v_buff_size size = size1;
|
||||
if(size2 < size1) size = size2;
|
||||
|
||||
for(v_buff_size i = 0; i < size; i ++) {
|
||||
|
||||
v_char8 a = d1[i] | 32;
|
||||
v_char8 b = d2[i] | 32;
|
||||
|
||||
if(a != b) {
|
||||
return (int) a - (int) b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(size1 < size2) return -1;
|
||||
if(size1 > size2) return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(const void* data1, const void* data2, v_buff_size size) {
|
||||
if(data1 == data2) return true;
|
||||
if(data1 == nullptr || data2 == nullptr) return false;
|
||||
return std::memcmp(data1, data2, size) == 0;
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(const char* data1, const char* data2) {
|
||||
if(data1 == data2) return true;
|
||||
if(data1 == nullptr || data2 == nullptr) return false;
|
||||
const auto size = std::strlen(data1);
|
||||
return (size == std::strlen(data2) && std::memcmp(data1, data2, size) == 0);
|
||||
}
|
||||
|
||||
bool StrBuffer::equals(StrBuffer* str1, StrBuffer* str2) {
|
||||
if(str1 == str2) return true;
|
||||
if(str1 == nullptr || str2 == nullptr) return false;
|
||||
if(str1->m_size != str2->m_size) return false;
|
||||
return str1->m_data == str2->m_data || std::memcmp(str1->m_data, str2->m_data, str1->m_size) == 0;
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI(const void* data1, const void* data2, v_buff_size size) {
|
||||
for(v_buff_size i = 0; i < size; i++) {
|
||||
v_char8 a = ((p_char8) data1) [i];
|
||||
v_char8 b = ((p_char8) data2) [i];
|
||||
if(a >= 'A' && a <= 'Z') a |= 32;
|
||||
if(b >= 'A' && b <= 'Z') b |= 32;
|
||||
if(a != b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI(const char* data1, const char* data2) {
|
||||
if(data1 == data2) return true;
|
||||
if(data1 == nullptr || data2 == nullptr) return false;
|
||||
const auto size = std::strlen(data1);
|
||||
return (size == std::strlen(data2) && equalsCI(data1, data2, size) == 0);
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI(StrBuffer* str1, StrBuffer* str2) {
|
||||
if(str1 == str2) return true;
|
||||
if(str1 == nullptr || str2 == nullptr) return false;
|
||||
if(str1->m_size != str2->m_size) return false;
|
||||
return (str1->m_data == str2->m_data || equalsCI(str1->m_data, str2->m_data, str1->m_size));
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI_FAST(const void* data1, const void* data2, v_buff_size size) {
|
||||
for(v_buff_size i = 0; i < size; i++) {
|
||||
if((((p_char8) data1) [i] | 32) != (((p_char8) data2) [i] | 32)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI_FAST(const char* data1, const char* data2) {
|
||||
if(data1 == data2) return true;
|
||||
if(data1 == nullptr || data2 == nullptr) return false;
|
||||
const auto size = std::strlen(data1);
|
||||
return (size == std::strlen(data2) && equalsCI_FAST(data1, data2, size) == 0);
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI_FAST(StrBuffer* str1, StrBuffer* str2) {
|
||||
if(str1 == str2) return true;
|
||||
if(str1 == nullptr || str2 == nullptr) return false;
|
||||
if(str1->m_size != str2->m_size) return false;
|
||||
return (str1->m_data == str2->m_data || equalsCI_FAST(str1->m_data, str2->m_data, str1->m_size));
|
||||
}
|
||||
|
||||
bool StrBuffer::equalsCI_FAST(StrBuffer* str1, const char* str2) {
|
||||
v_buff_size len = std::strlen(str2);
|
||||
return (str1->getSize() == len && equalsCI_FAST(str1->m_data, str2, str1->m_size));
|
||||
}
|
||||
|
||||
void StrBuffer::lowerCase(const 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 StrBuffer::upperCase(const 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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
@ -1,391 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_base_StrBuffer_hpp
|
||||
#define oatpp_base_StrBuffer_hpp
|
||||
|
||||
#include "memory/ObjectPool.hpp"
|
||||
#include "./Countable.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace oatpp { namespace base {
|
||||
|
||||
/**
|
||||
* String buffer class.
|
||||
*/
|
||||
class StrBuffer : public oatpp::base::Countable {
|
||||
private:
|
||||
|
||||
static constexpr v_buff_size SM_STRING_POOL_ENTRY_SIZE = 256;
|
||||
|
||||
static memory::ThreadDistributedMemoryPool& getSmallStringPool() {
|
||||
static auto pool = new memory::ThreadDistributedMemoryPool("Small_String_Pool", SM_STRING_POOL_ENTRY_SIZE, 16);
|
||||
return *pool;
|
||||
}
|
||||
|
||||
static v_buff_size getSmStringBaseSize() {
|
||||
memory::AllocationExtras extras(0);
|
||||
auto ptr = memory::customPoolAllocateSharedWithExtras<StrBuffer>(extras, getSmallStringPool());
|
||||
return extras.baseSize;
|
||||
}
|
||||
|
||||
static v_buff_size getSmStringSize() {
|
||||
static v_buff_size size = SM_STRING_POOL_ENTRY_SIZE - getSmStringBaseSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
p_char8 m_data;
|
||||
v_buff_size m_size;
|
||||
bool m_hasOwnData;
|
||||
private:
|
||||
|
||||
void set(const void* data, v_buff_size size, bool hasOwnData);
|
||||
void setAndCopy(const void* data, const void* originData, v_buff_size size);
|
||||
static std::shared_ptr<StrBuffer> allocShared(const void* data, v_buff_size size, bool copyAsOwnData);
|
||||
|
||||
/*
|
||||
* Allocate memory for string or use originData<br>
|
||||
* if copyAsOwnData == false return originData
|
||||
*/
|
||||
static p_char8 allocStrBuffer(const void* originData, v_buff_size size, bool copyAsOwnData);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor. Default.
|
||||
*/
|
||||
StrBuffer();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param data - pointer to data.
|
||||
* @param size - size of the data.
|
||||
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
|
||||
*/
|
||||
StrBuffer(const void* data, v_buff_size size, bool copyAsOwnData);
|
||||
public:
|
||||
|
||||
/**
|
||||
* virtual Destructor.
|
||||
*/
|
||||
virtual ~StrBuffer();
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer of specified size.
|
||||
* @param size - size of the buffer.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createShared(v_buff_size size);
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer with data, size, and copyAsOwnData parameters.
|
||||
* @param data - buffer data.
|
||||
* @param size - size of the data.
|
||||
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createShared(const void* data, v_buff_size size, bool copyAsOwnData = true);
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer with data, and copyAsOwnData parameters.
|
||||
* @param data - buffer data.
|
||||
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createShared(const char* data, bool copyAsOwnData = true);
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer from other StrBuffer.
|
||||
* @param other - other StrBuffer.
|
||||
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createShared(StrBuffer* other, bool copyAsOwnData = true);
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer of size=size1 + size2 and data=data1 + data2.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param size1 - size of the data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of the data2.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createSharedConcatenated(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
|
||||
|
||||
/**
|
||||
* Create shared StrBuffer from c-string.
|
||||
* @param data - data.
|
||||
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> createFromCString(const char* data, bool copyAsOwnData = true) {
|
||||
if(data != nullptr) {
|
||||
return allocShared(data, std::strlen(data), copyAsOwnData);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from file and store in StrBuffer.
|
||||
* @param filename - name of the file.
|
||||
* @return - shared_ptr to StrBuffer.
|
||||
*/
|
||||
static std::shared_ptr<StrBuffer> loadFromFile(const char* filename);
|
||||
|
||||
/**
|
||||
* Save content of the buffer to file.
|
||||
* @param filename - name of the file.
|
||||
*/
|
||||
void saveToFile(const char* filename);
|
||||
|
||||
/**
|
||||
* Get pointer to data of the buffer.
|
||||
* @return - pointer to data of the buffer.
|
||||
*/
|
||||
p_char8 getData() const;
|
||||
|
||||
/**
|
||||
* Get buffer size.
|
||||
* @return - buffer size.
|
||||
*/
|
||||
v_buff_size getSize() const;
|
||||
|
||||
/**
|
||||
* Get pointer to data of the buffer as `const* char`.
|
||||
* @return - pointer to data of the buffer.
|
||||
*/
|
||||
const char* c_str() const;
|
||||
|
||||
/**
|
||||
* Get copy of the buffer data as `std::string`.
|
||||
* @return - copy of the buffer data as `std::string`.
|
||||
*/
|
||||
std::string std_str() const;
|
||||
|
||||
/**
|
||||
* Is this object is responsible for freeing buffer data.
|
||||
* @return - true if this object is responsible for freeing buffer data.
|
||||
*/
|
||||
bool hasOwnData() const;
|
||||
|
||||
/**
|
||||
* Create lowercase copy of the buffer.<br>
|
||||
* (correct for ASCII only)
|
||||
* @return - copy of the buffer containing lowercase variants of ascii symbols.
|
||||
*/
|
||||
std::shared_ptr<StrBuffer> toLowerCase() const;
|
||||
|
||||
/**
|
||||
* Create uppercase copy of the buffer.<br>
|
||||
* (correct for ASCII only)
|
||||
* @return - copy of the buffer containing uppercase variants of ascii symbols.
|
||||
*/
|
||||
std::shared_ptr<StrBuffer> toUpperCase() const;
|
||||
|
||||
/**
|
||||
* Check string equality of the buffer to data of specified size.
|
||||
* @param data - pointer to data to be compared with the buffer data.
|
||||
* @param size - size of the data.
|
||||
* @return - true if all chars of buffer are same as in data, and size == this.getSize().
|
||||
*/
|
||||
bool equals(const void* data, v_buff_size size) const;
|
||||
|
||||
/**
|
||||
* Check string equality of the buffer to data of specified size.
|
||||
* @param data - pointer to data to be compared with the buffer data.
|
||||
* @return - true if all chars of buffer are same as in data, and std::strlen(data) == this.getSize().
|
||||
*/
|
||||
bool equals(const char* data) const;
|
||||
|
||||
/**
|
||||
* Check string equality to other buffer.
|
||||
* @param other - pointer to other StrBuffer to be compared with the buffer data.
|
||||
* @return - true if all chars of one buffer are same as in other, and other.getSize() == this.getSize().
|
||||
*/
|
||||
bool equals(StrBuffer* other) const;
|
||||
|
||||
/**
|
||||
* Check if buffer starts with specified data, size.
|
||||
* @param data - data as `const void*`.
|
||||
* @param size - size of the data.
|
||||
* @return - true if buffer starts with specified data.
|
||||
*/
|
||||
bool startsWith(const void* data, v_buff_size size) const;
|
||||
|
||||
/**
|
||||
* Check if buffer starts with specified data.
|
||||
* @param data - data as `const char*`.
|
||||
* @return - true if buffer starts with specified data.
|
||||
*/
|
||||
bool startsWith(const char* data) const;
|
||||
|
||||
/**
|
||||
* Check if buffer starts with specified data.
|
||||
* @param data - data as `StrBuffer`.
|
||||
* @return - true if buffer starts with specified data.
|
||||
*/
|
||||
bool startsWith(StrBuffer* data) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Compare data1, data2 using `std::memcmp`.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param size1 - size of data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of data2.
|
||||
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
|
||||
* 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 compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
|
||||
|
||||
/**
|
||||
* Compare data1, data2 - case insensitive.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param size1 - size of data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of data2.
|
||||
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Compare data1, data2 - case insensitive (ASCII only, correct compare if one of strings contains letters only).
|
||||
* @param data1 - pointer to data1.
|
||||
* @param size1 - size of data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of data2.s
|
||||
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
|
||||
* 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_FAST(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
|
||||
|
||||
/**
|
||||
* Check string equality of data1 to data2.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size - number of characters to compare.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equals(const void* data1, const void* data2, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Check string equality of data1 to data2.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equals(const char* data1, const char* data2);
|
||||
|
||||
/**
|
||||
* Check string equality of str1 to str2.
|
||||
* @param str1 - pointer to str1.
|
||||
* @param str2 - pointer to str2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equals(StrBuffer* str1, StrBuffer* str2);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of data1 to data2.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size - number of characters to compare.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI(const void* data1, const void* data2, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of data1 to data2.
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI(const char* data1, const char* data2);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of str1 to str2.
|
||||
* @param str1 - pointer to str1.
|
||||
* @param str2 - pointer to str2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI(StrBuffer* str1, StrBuffer* str2);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of data1 to data2. (ASCII only, correct compare if one of strings contains letters only)
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size - number of characters to compare.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI_FAST(const void* data1, const void* data2, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of data1 to data2. (ASCII only, correct compare if one of strings contains letters only)
|
||||
* @param data1 - pointer to data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI_FAST(const char* data1, const char* data2);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of str1 to str2. (ASCII only, correct compare if one of strings contains letters only)
|
||||
* @param str1 - pointer to str1.
|
||||
* @param str2 - pointer to str2.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI_FAST(StrBuffer* str1, StrBuffer* str2);
|
||||
|
||||
/**
|
||||
* Check Case Insensitive string equality of str1 to str2. (ASCII only, correct compare if one of strings contains letters only)
|
||||
* @param str1 - pointer to str1 as `StrBuffer`.
|
||||
* @param str2 - pointer to str2 as `const char*`
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
static bool equalsCI_FAST(StrBuffer* str1, const char* str2);
|
||||
|
||||
/**
|
||||
* Change characters in data to lowercase.
|
||||
* @param data - pointer to data.
|
||||
* @param size - size of the data.
|
||||
*/
|
||||
static void lowerCase(const void* data, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Change characters in data to uppercase.
|
||||
* @param data - pointer to data.
|
||||
* @param size - size of the data.
|
||||
*/
|
||||
static void upperCase(const void* data, v_buff_size size);
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* oatpp_base_StrBuffer_hpp */
|
@ -1,281 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_collection_LinkedList_hpp
|
||||
#define oatpp_collection_LinkedList_hpp
|
||||
|
||||
#include "oatpp/core/base/memory/ObjectPool.hpp"
|
||||
|
||||
|
||||
#include "oatpp/core/base/Countable.hpp"
|
||||
#include "oatpp/core/base/Environment.hpp"
|
||||
|
||||
namespace oatpp { namespace collection {
|
||||
|
||||
template<class T>
|
||||
class LinkedList : public base::Countable {
|
||||
public:
|
||||
OBJECT_POOL(LinkedList_Pool, LinkedList, 32)
|
||||
SHARED_OBJECT_POOL(Shared_LinkedList_Pool, LinkedList, 32)
|
||||
public:
|
||||
|
||||
class LinkedListNode {
|
||||
friend LinkedList;
|
||||
friend oatpp::base::memory::MemoryPool;
|
||||
public:
|
||||
OBJECT_POOL_THREAD_LOCAL(LinkedList_Node_Pool, LinkedListNode, 32)
|
||||
private:
|
||||
T data;
|
||||
LinkedListNode* next;
|
||||
|
||||
protected:
|
||||
|
||||
LinkedListNode(const T& nodeData, LinkedListNode* nextNode)
|
||||
: data(nodeData)
|
||||
, next(nextNode)
|
||||
{}
|
||||
|
||||
~LinkedListNode(){
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const T& getData(){
|
||||
return data;
|
||||
}
|
||||
|
||||
LinkedListNode* getNext(){
|
||||
return next;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
LinkedListNode* m_first;
|
||||
LinkedListNode* m_last;
|
||||
v_int32 m_count;
|
||||
oatpp::base::memory::MemoryPool& m_itemMemoryPool;
|
||||
|
||||
LinkedListNode* createNode(const T& data, LinkedListNode* next){
|
||||
return new (m_itemMemoryPool.obtain()) LinkedListNode(data, next);
|
||||
}
|
||||
|
||||
void destroyNode(LinkedListNode* node){
|
||||
node->~LinkedListNode();
|
||||
oatpp::base::memory::MemoryPool::free(node);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
LinkedList()
|
||||
: m_first(nullptr)
|
||||
, m_last(nullptr)
|
||||
, m_count(0)
|
||||
, m_itemMemoryPool(LinkedListNode::LinkedList_Node_Pool::getPool())
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
static std::shared_ptr<LinkedList> createShared(){
|
||||
return Shared_LinkedList_Pool::allocateShared();
|
||||
}
|
||||
|
||||
static std::shared_ptr<LinkedList> copy(LinkedList<T>* other){
|
||||
auto result = createShared();
|
||||
auto curr = other->m_first;
|
||||
while(curr != nullptr){
|
||||
result->pushBack(curr->data);
|
||||
curr = curr->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual ~LinkedList() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void pushFront(const T& data){
|
||||
|
||||
if(m_first == nullptr){
|
||||
LinkedListNode* newNode = createNode(data, nullptr);
|
||||
m_first = newNode;
|
||||
m_last = newNode;
|
||||
}else{
|
||||
LinkedListNode* newNode = createNode(data, m_first);
|
||||
m_first = newNode;
|
||||
}
|
||||
m_count++;
|
||||
|
||||
}
|
||||
|
||||
void pushBack(const T& data){
|
||||
|
||||
LinkedListNode* newNode = createNode(data, nullptr);
|
||||
|
||||
if(m_last == nullptr){
|
||||
m_first = newNode;
|
||||
m_last = newNode;
|
||||
}else{
|
||||
m_last->next = newNode;
|
||||
m_last = newNode;
|
||||
}
|
||||
|
||||
m_count++;
|
||||
|
||||
}
|
||||
|
||||
void pushBackAll(const std::shared_ptr<LinkedList>& list){
|
||||
auto curr = list->getFirstNode();
|
||||
while(curr != nullptr) {
|
||||
pushBack(curr->getData());
|
||||
curr = curr->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
void insertAfterNode(const T& data, LinkedListNode* currentNode){
|
||||
LinkedListNode* node = createNode(data, currentNode->next);
|
||||
currentNode->next = node;
|
||||
if(currentNode == m_last){
|
||||
m_last = node;
|
||||
}
|
||||
m_count++;
|
||||
}
|
||||
|
||||
T popFront(){
|
||||
if(m_first != nullptr){
|
||||
LinkedListNode* node = m_first;
|
||||
m_first = m_first->next;
|
||||
if(m_first == nullptr){
|
||||
m_last = nullptr;
|
||||
}
|
||||
m_count --;
|
||||
T result = node->data;
|
||||
destroyNode(node);
|
||||
return result;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::collection::LinkedList::popFront()]: index out of bounds");
|
||||
}
|
||||
|
||||
const T& getFirst() const{
|
||||
return m_first->data;
|
||||
}
|
||||
|
||||
const T& getLast() const{
|
||||
return m_last->data;
|
||||
}
|
||||
|
||||
const T& get(v_int32 index) const{
|
||||
|
||||
LinkedListNode* node = getNode(index);
|
||||
if(node != nullptr){
|
||||
return node->data;
|
||||
}
|
||||
|
||||
throw std::runtime_error("[oatpp::collection::LinkedList::get(index)]: index out of bounds");
|
||||
|
||||
}
|
||||
|
||||
LinkedListNode* getNode(v_int32 index) const {
|
||||
|
||||
if(index >= m_count){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
v_int32 i = 0;
|
||||
LinkedListNode* curr = m_first;
|
||||
|
||||
while(curr != nullptr){
|
||||
|
||||
if(i == index){
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr = curr->next;
|
||||
i++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
LinkedListNode* getFirstNode() const {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
v_int32 count() const{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* for each item call a function
|
||||
*
|
||||
* list->forEachNode([](auto item){
|
||||
* // your code here
|
||||
* });
|
||||
*/
|
||||
template<typename F>
|
||||
void forEach(const F& lambda) const {
|
||||
auto curr = m_first;
|
||||
while(curr != nullptr) {
|
||||
lambda(curr->data);
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for each node call a function
|
||||
*
|
||||
* list->forEachNode([](auto node){
|
||||
* // your code here
|
||||
* });
|
||||
*/
|
||||
template<typename F>
|
||||
void forEachNode(const F& lambda) const {
|
||||
auto curr = m_first;
|
||||
while(curr != nullptr) {
|
||||
lambda(curr);
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
|
||||
void clear(){
|
||||
|
||||
LinkedListNode* curr = m_first;
|
||||
while(curr != nullptr){
|
||||
LinkedListNode* next = curr->next;
|
||||
destroyNode(curr);
|
||||
curr = next;
|
||||
}
|
||||
|
||||
m_first = nullptr;
|
||||
m_last = nullptr;
|
||||
m_count = 0;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* oatpp_collection_LinkedList_hpp */
|
@ -1,277 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_collection_ListMap_hpp
|
||||
#define oatpp_collection_ListMap_hpp
|
||||
|
||||
#include "oatpp/core/base/memory/ObjectPool.hpp"
|
||||
#include "oatpp/core/base/Countable.hpp"
|
||||
|
||||
namespace oatpp { namespace collection {
|
||||
|
||||
template<class K, class V>
|
||||
class ListMap : public oatpp::base::Countable {
|
||||
public:
|
||||
OBJECT_POOL(ListMap_Pool, ListMap, 32)
|
||||
SHARED_OBJECT_POOL(Shared_ListMap_Pool, ListMap, 32)
|
||||
public:
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Entry
|
||||
|
||||
class Entry{
|
||||
friend ListMap;
|
||||
public:
|
||||
OBJECT_POOL_THREAD_LOCAL(ListMap_Entry_Pool, Entry, 64)
|
||||
private:
|
||||
K key;
|
||||
V value;
|
||||
Entry* next;
|
||||
protected:
|
||||
Entry(const K& pKey, const V& pValue, Entry* pNext)
|
||||
: key(pKey)
|
||||
, value(pValue)
|
||||
, next(pNext)
|
||||
{}
|
||||
|
||||
~Entry(){
|
||||
}
|
||||
public:
|
||||
|
||||
const K& getKey() const{
|
||||
return key;
|
||||
}
|
||||
|
||||
const V& getValue() const{
|
||||
return value;
|
||||
}
|
||||
|
||||
Entry* getNext() const{
|
||||
return next;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Entry* m_first;
|
||||
Entry* m_last;
|
||||
v_int32 m_count;
|
||||
|
||||
oatpp::base::memory::MemoryPool& m_itemMemoryPool;
|
||||
|
||||
private:
|
||||
|
||||
Entry* createEntry(const K& pKey, const V& pValue, Entry* pNext){
|
||||
return new (m_itemMemoryPool.obtain()) Entry(pKey, pValue, pNext);
|
||||
}
|
||||
|
||||
void destroyEntry(Entry* entry){
|
||||
entry->~Entry();
|
||||
oatpp::base::memory::MemoryPool::free(entry);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<class Key>
|
||||
Entry* getEntryByKey(const Key& key) const{
|
||||
|
||||
Entry* curr = m_first;
|
||||
|
||||
while(curr != nullptr){
|
||||
if(key == curr->key){
|
||||
return curr;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void addOneEntry(Entry* entry){
|
||||
|
||||
if(m_last == nullptr){
|
||||
m_first = entry;
|
||||
m_last = entry;
|
||||
}else{
|
||||
m_last->next = entry;
|
||||
m_last = entry;
|
||||
}
|
||||
|
||||
m_count++;
|
||||
}
|
||||
|
||||
public:
|
||||
ListMap()
|
||||
: m_first(nullptr)
|
||||
, m_last(nullptr)
|
||||
, m_count(0)
|
||||
, m_itemMemoryPool(Entry::ListMap_Entry_Pool::getPool())
|
||||
{}
|
||||
public:
|
||||
|
||||
static std::shared_ptr<ListMap> createShared(){
|
||||
return Shared_ListMap_Pool::allocateShared();
|
||||
}
|
||||
|
||||
~ListMap() override {
|
||||
clear();
|
||||
}
|
||||
|
||||
Entry* put(const K& key, const V& value){
|
||||
Entry* entry = getEntryByKey(key);
|
||||
if(entry != nullptr){
|
||||
if(entry->value != value){
|
||||
entry->value = value;
|
||||
}
|
||||
}else{
|
||||
entry = createEntry(key, value, nullptr);
|
||||
addOneEntry(entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool putIfNotExists(const K& key, const V& value){
|
||||
Entry* entry = getEntryByKey(key);
|
||||
if(entry == nullptr){
|
||||
entry = createEntry(key, value, nullptr);
|
||||
addOneEntry(entry);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Entry* find(const K& key) const{
|
||||
Entry* entry = getEntryByKey<K>(key);
|
||||
if(entry != nullptr){
|
||||
return entry;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const V& get(const K& key, const V& defaultValue) const {
|
||||
Entry* entry = getEntryByKey<K>(key);
|
||||
if(entry != nullptr){
|
||||
return entry->getValue();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/*
|
||||
template <class Key>
|
||||
const Entry* getByKeyTemplate(const Key& key) const{
|
||||
|
||||
Entry* entry = getEntryByKey(key);
|
||||
if(entry != nullptr){
|
||||
return entry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
V remove(const K& key){
|
||||
|
||||
if(m_first != nullptr){
|
||||
|
||||
if(m_first->key->equals(key)){
|
||||
Entry* next = m_first->next;
|
||||
V result = m_first->value;
|
||||
destroyEntry(m_first);
|
||||
m_first = next;
|
||||
return result;
|
||||
}
|
||||
|
||||
Entry* curr = m_first;
|
||||
Entry* next = m_first->next;
|
||||
|
||||
while(next != nullptr){
|
||||
if(next->key->equals(key)){
|
||||
V result = next->value;
|
||||
curr->next = next->next;
|
||||
destroyEntry(next);
|
||||
return result;
|
||||
}
|
||||
curr = next;
|
||||
next = curr->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return V::empty();
|
||||
}
|
||||
|
||||
Entry* getEntryByIndex(v_int32 index) const{
|
||||
|
||||
if(index >= m_count){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
v_int32 i = 0;
|
||||
Entry* curr = m_first;
|
||||
|
||||
while(curr != nullptr){
|
||||
|
||||
if(i == index){
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr = curr->next;
|
||||
i++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
Entry* getFirstEntry() const {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
v_int32 count() const{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
|
||||
Entry* curr = m_first;
|
||||
while(curr != nullptr){
|
||||
Entry* next = curr->next;
|
||||
destroyEntry(curr);
|
||||
curr = next;
|
||||
}
|
||||
|
||||
m_first = nullptr;
|
||||
m_last = nullptr;
|
||||
m_count = 0;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* oatpp_collection_ListMap_hpp */
|
37
src/oatpp/core/data/Bundle.cpp
Normal file
37
src/oatpp/core/data/Bundle.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "Bundle.hpp"
|
||||
|
||||
namespace oatpp { namespace data {
|
||||
|
||||
void Bundle::put(const oatpp::String& key, const oatpp::Void& polymorph) {
|
||||
m_data.insert({key, polymorph});
|
||||
}
|
||||
|
||||
const std::unordered_map<oatpp::String, oatpp::Void>& Bundle::getAll() const {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
}}
|
90
src/oatpp/core/data/Bundle.hpp
Normal file
90
src/oatpp/core/data/Bundle.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_data_Bundle_hpp
|
||||
#define oatpp_data_Bundle_hpp
|
||||
|
||||
#include "oatpp/core/Types.hpp"
|
||||
|
||||
namespace oatpp { namespace data {
|
||||
|
||||
/**
|
||||
* Bundle of auxiliary data.
|
||||
*/
|
||||
class Bundle {
|
||||
private:
|
||||
std::unordered_map<oatpp::String, oatpp::Void> m_data;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
Bundle() = default;
|
||||
|
||||
/**
|
||||
* Default virtual destructor.
|
||||
*/
|
||||
virtual ~Bundle() = default;
|
||||
|
||||
/**
|
||||
* Put data by key.
|
||||
* @param key
|
||||
* @param polymorph
|
||||
*/
|
||||
void put(const oatpp::String& key, const oatpp::Void& polymorph);
|
||||
|
||||
/**
|
||||
* Get data by key.
|
||||
* @tparam WrapperType
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
template<typename WrapperType>
|
||||
WrapperType get(const oatpp::String& key) const {
|
||||
auto it = m_data.find(key);
|
||||
if(it == m_data.end()) {
|
||||
throw std::runtime_error("[oatpp::data::Bundle::get()]: "
|
||||
"Error. Data not found for key '" + *key + "'.");
|
||||
}
|
||||
|
||||
if(it->second.getValueType() != WrapperType::Class::getType()) {
|
||||
throw std::runtime_error("[oatpp::data::Bundle::get()]: Error. Type mismatch for key '" + *key +
|
||||
"'. Stored '" +
|
||||
std::string(it->second.getValueType()->classId.name) +
|
||||
"' vs requested '" + std::string(WrapperType::Class::getType()->classId.name) + "'.");
|
||||
}
|
||||
return it->second.template staticCast<WrapperType>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map of data stored in the bundle.
|
||||
* @return
|
||||
*/
|
||||
const std::unordered_map<oatpp::String, oatpp::Void>& getAll() const;
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //oatpp_data_Bundle_hpp
|
@ -246,7 +246,7 @@ v_io_size FIFOBuffer::write(const void *data, v_buff_size count) {
|
||||
|
||||
}
|
||||
|
||||
v_io_size FIFOBuffer::readAndWriteToStream(data::stream::OutputStream* stream, v_buff_size count, async::Action& action) {
|
||||
v_io_size FIFOBuffer::readAndWriteToStream(data::stream::WriteCallback* stream, v_buff_size count, async::Action& action) {
|
||||
|
||||
if(!m_canRead) {
|
||||
return IOError::RETRY_READ;
|
||||
@ -299,7 +299,7 @@ v_io_size FIFOBuffer::readAndWriteToStream(data::stream::OutputStream* stream, v
|
||||
|
||||
}
|
||||
|
||||
v_io_size FIFOBuffer::readFromStreamAndWrite(data::stream::InputStream* stream, v_buff_size count, async::Action& action) {
|
||||
v_io_size FIFOBuffer::readFromStreamAndWrite(data::stream::ReadCallback* stream, v_buff_size count, async::Action& action) {
|
||||
|
||||
if(m_canRead && m_writePosition == m_readPosition) {
|
||||
return IOError::RETRY_WRITE;
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
* @param action
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size readAndWriteToStream(data::stream::OutputStream* stream, v_buff_size count, async::Action& action);
|
||||
v_io_size readAndWriteToStream(data::stream::WriteCallback* stream, v_buff_size count, async::Action& action);
|
||||
|
||||
/**
|
||||
* call stream.read() and then write bytes read to buffer
|
||||
@ -132,7 +132,7 @@ public:
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
v_io_size readFromStreamAndWrite(data::stream::InputStream* stream, v_buff_size count, async::Action& action);
|
||||
v_io_size readFromStreamAndWrite(data::stream::ReadCallback* stream, v_buff_size count, async::Action& action);
|
||||
|
||||
/**
|
||||
* flush all availableToRead bytes to stream
|
||||
|
@ -24,7 +24,9 @@
|
||||
|
||||
#include "IOBuffer.hpp"
|
||||
|
||||
namespace oatpp { namespace data{ namespace buffer {
|
||||
namespace oatpp { namespace data { namespace buffer {
|
||||
|
||||
const v_buff_size IOBuffer::BUFFER_SIZE = 4096;
|
||||
|
||||
IOBuffer::IOBuffer()
|
||||
: m_entry(getBufferPool().obtain())
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
/**
|
||||
* Buffer size constant.
|
||||
*/
|
||||
static constexpr v_buff_size BUFFER_SIZE = 4096;
|
||||
static const v_buff_size BUFFER_SIZE;
|
||||
private:
|
||||
static oatpp::base::memory::ThreadDistributedMemoryPool& getBufferPool() {
|
||||
static auto pool = new oatpp::base::memory::ThreadDistributedMemoryPool("IOBuffer_Buffer_Pool", BUFFER_SIZE, 16);
|
||||
|
@ -129,15 +129,15 @@ const type::Type* TypeResolver::resolveType(const type::Type* type, Cache& cache
|
||||
|
||||
type::Void TypeResolver::resolveValue(const type::Void& value, Cache& cache) const {
|
||||
|
||||
if(value.valueType == nullptr) {
|
||||
if(value.getValueType() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(isKnownClass(value.valueType->classId)) {
|
||||
if(isKnownClass(value.getValueType()->classId)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
auto typeIt = cache.values.find(value.valueType);
|
||||
auto typeIt = cache.values.find(value.getValueType());
|
||||
if(typeIt != cache.values.end()) {
|
||||
auto valueIt = typeIt->second.find(value);
|
||||
if(valueIt != typeIt->second.end()) {
|
||||
@ -145,10 +145,10 @@ type::Void TypeResolver::resolveValue(const type::Void& value, Cache& cache) con
|
||||
}
|
||||
}
|
||||
|
||||
auto interpretation = value.valueType->findInterpretation(m_enabledInterpretations);
|
||||
auto interpretation = value.getValueType()->findInterpretation(m_enabledInterpretations);
|
||||
if(interpretation) {
|
||||
auto resolution = resolveValue(interpretation->toInterpretation(value), cache);
|
||||
cache.values[value.valueType].insert({value, resolution});
|
||||
cache.values[value.getValueType()].insert({value, resolution});
|
||||
return resolution;
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ type::Void TypeResolver::findPropertyValue(const type::Void& baseObject,
|
||||
Cache& cache) const
|
||||
{
|
||||
|
||||
auto baseType = baseObject.valueType;
|
||||
auto baseType = baseObject.getValueType();
|
||||
|
||||
if(isKnownType(baseType)) {
|
||||
if(pathPosition == path.size()) {
|
||||
@ -221,7 +221,7 @@ type::Void TypeResolver::findPropertyValue(const type::Void& baseObject,
|
||||
}
|
||||
|
||||
const auto& resolution = resolveValue(baseObject, cache);
|
||||
if(resolution.valueType->classId.id != type::Void::Class::CLASS_ID.id) {
|
||||
if(resolution.getValueType()->classId.id != type::Void::Class::CLASS_ID.id) {
|
||||
return findPropertyValue(resolution, path, pathPosition, cache);
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,6 @@
|
||||
|
||||
#include "./Type.hpp"
|
||||
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
|
||||
#include "oatpp/core/base/memory/ObjectPool.hpp"
|
||||
#include "oatpp/core/base/Countable.hpp"
|
||||
|
||||
@ -107,7 +105,7 @@ public:
|
||||
*/
|
||||
template<class T, class C>
|
||||
Any(const ObjectWrapper<T, C>& polymorph)
|
||||
: ObjectWrapper(std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.valueType), __class::Any::getType())
|
||||
: ObjectWrapper(std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.getValueType()), __class::Any::getType())
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -118,7 +116,7 @@ public:
|
||||
*/
|
||||
template<class T, class C>
|
||||
void store(const ObjectWrapper<T, C>& polymorph) {
|
||||
m_ptr = std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.valueType);
|
||||
m_ptr = std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.getValueType());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,7 +155,7 @@ public:
|
||||
|
||||
template<class T, class C>
|
||||
Any& operator=(const ObjectWrapper<T, C>& polymorph) {
|
||||
m_ptr = std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.valueType);
|
||||
m_ptr = std::make_shared<AnyHandle>(polymorph.getPtr(), polymorph.getValueType());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ template<class T, bool notnull>
|
||||
Void EnumInterpreterAsString<T, notnull>::toInterpretation(const Void& enumValue, EnumInterpreterError& error) {
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsString<T, notnull>> EnumOW;
|
||||
|
||||
if(enumValue.valueType != EnumOW::Class::getType()) {
|
||||
if(enumValue.getValueType() != EnumOW::Class::getType()) {
|
||||
error = EnumInterpreterError::TYPE_MISMATCH_ENUM;
|
||||
return Void(nullptr, String::Class::getType());
|
||||
}
|
||||
@ -481,7 +481,7 @@ template<class T, bool notnull>
|
||||
Void EnumInterpreterAsString<T, notnull>::fromInterpretation(const Void& interValue, EnumInterpreterError& error) {
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsString<T, notnull>> EnumOW;
|
||||
|
||||
if(interValue.valueType != String::Class::getType()) {
|
||||
if(interValue.getValueType() != String::Class::getType()) {
|
||||
error = EnumInterpreterError::TYPE_MISMATCH_ENUM_VALUE;
|
||||
return Void(nullptr, EnumOW::Class::getType());
|
||||
}
|
||||
@ -515,7 +515,7 @@ Void EnumInterpreterAsNumber<T, notnull>::toInterpretation(const Void& enumValue
|
||||
typedef typename std::underlying_type<T>::type EnumUT;
|
||||
typedef typename ObjectWrapperByUnderlyingType<EnumUT>::ObjectWrapper UTOW;
|
||||
|
||||
if(enumValue.valueType != EnumOW::Class::getType()) {
|
||||
if(enumValue.getValueType() != EnumOW::Class::getType()) {
|
||||
error = EnumInterpreterError::TYPE_MISMATCH_ENUM;
|
||||
return Void(nullptr, UTOW::Class::getType());
|
||||
}
|
||||
@ -540,7 +540,7 @@ Void EnumInterpreterAsNumber<T, notnull>::fromInterpretation(const Void& interVa
|
||||
typedef typename std::underlying_type<T>::type EnumUT;
|
||||
typedef typename ObjectWrapperByUnderlyingType<EnumUT>::ObjectWrapper OW;
|
||||
|
||||
if(interValue.valueType != OW::Class::getType()) {
|
||||
if(interValue.getValueType() != OW::Class::getType()) {
|
||||
error = EnumInterpreterError::TYPE_MISMATCH_ENUM_VALUE;
|
||||
return Void(nullptr, EnumOW::Class::getType());
|
||||
}
|
||||
|
@ -24,28 +24,77 @@
|
||||
|
||||
#include "./Primitive.hpp"
|
||||
|
||||
#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 {
|
||||
|
||||
String::String(const std::shared_ptr<oatpp::base::StrBuffer>& ptr, const type::Type* const valueType)
|
||||
: oatpp::data::mapping::type::ObjectWrapper<oatpp::base::StrBuffer, __class::String>(ptr)
|
||||
String::String(const std::shared_ptr<std::string>& ptr, const type::Type* const valueType)
|
||||
: oatpp::data::mapping::type::ObjectWrapper<std::string, __class::String>(ptr)
|
||||
{
|
||||
if(type::__class::String::getType() != valueType) {
|
||||
throw std::runtime_error("Value type does not match");
|
||||
}
|
||||
}
|
||||
|
||||
String operator + (const char* a, const String& b) {
|
||||
return oatpp::base::StrBuffer::createSharedConcatenated(a, (v_int32) std::strlen(a), b->getData(), b->getSize());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
String operator + (const String& b, const char* a) {
|
||||
return oatpp::base::StrBuffer::createSharedConcatenated(b->getData(), b->getSize(), a, (v_int32) std::strlen(a));
|
||||
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;
|
||||
return stream.toString();
|
||||
}
|
||||
|
||||
String operator + (const String& a, const char* b) {
|
||||
data::stream::BufferOutputStream stream;
|
||||
stream << a << b;
|
||||
return stream.toString();
|
||||
}
|
||||
|
||||
String operator + (const String& a, const String& b) {
|
||||
return oatpp::base::StrBuffer::createSharedConcatenated(a->getData(), a->getSize(), b->getData(), b->getSize());
|
||||
data::stream::BufferOutputStream stream;
|
||||
stream << a << b;
|
||||
return stream.toString();
|
||||
}
|
||||
|
||||
namespace __class {
|
||||
|
@ -29,12 +29,15 @@
|
||||
|
||||
#include "oatpp/core/base/memory/ObjectPool.hpp"
|
||||
#include "oatpp/core/base/Countable.hpp"
|
||||
#include "oatpp/core/base/StrBuffer.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <iterator>
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping { namespace type {
|
||||
|
||||
|
||||
namespace __class {
|
||||
|
||||
|
||||
class String; // FWD
|
||||
|
||||
class Int8; // FWD
|
||||
@ -53,60 +56,125 @@ namespace __class {
|
||||
class Float64; // FWD
|
||||
|
||||
class Boolean; // FWD
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping-enables String is &id:type::ObjectWrapper; over &id:oatpp::base::StrBuffer;
|
||||
* Mapping-enables String is &id:type::ObjectWrapper; over `std::string`;
|
||||
*/
|
||||
class String : public type::ObjectWrapper<base::StrBuffer, __class::String> {
|
||||
class String : public type::ObjectWrapper<std::string, __class::String> {
|
||||
public:
|
||||
String(const std::shared_ptr<base::StrBuffer>& ptr, const type::Type* const valueType);
|
||||
String(const std::shared_ptr<std::string>& ptr, const type::Type* const valueType);
|
||||
public:
|
||||
|
||||
|
||||
String() {}
|
||||
|
||||
String(std::nullptr_t) {}
|
||||
|
||||
explicit String(v_buff_size size)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(base::StrBuffer::createShared(size))
|
||||
{}
|
||||
|
||||
String(const char* data, v_buff_size size, bool copyAsOwnData = true)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(base::StrBuffer::createShared(data, size, copyAsOwnData))
|
||||
{}
|
||||
|
||||
String(const char* data1, v_buff_size size1, const char* data2, v_buff_size size2)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(base::StrBuffer::createSharedConcatenated(data1, size1, data2, size2))
|
||||
{}
|
||||
|
||||
String(const char* data, bool copyAsOwnData = true)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(base::StrBuffer::createFromCString(data, copyAsOwnData))
|
||||
{}
|
||||
|
||||
String(const std::shared_ptr<base::StrBuffer>& ptr)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(ptr)
|
||||
{}
|
||||
|
||||
String(std::shared_ptr<base::StrBuffer>&& ptr)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(std::forward<std::shared_ptr<base::StrBuffer>>(ptr))
|
||||
{}
|
||||
|
||||
String(const String& other)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(other)
|
||||
{}
|
||||
|
||||
String(String&& other)
|
||||
: type::ObjectWrapper<base::StrBuffer, __class::String>(std::forward<String>(other))
|
||||
: type::ObjectWrapper<std::string, __class::String>(std::make_shared<std::string>(size, 0))
|
||||
{}
|
||||
|
||||
String(const char* data, v_buff_size size)
|
||||
: type::ObjectWrapper<std::string, __class::String>(std::make_shared<std::string>(data, size))
|
||||
{}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
String(T) {}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, char>::value, void>::type
|
||||
>
|
||||
String(const T* data)
|
||||
: type::ObjectWrapper<std::string, __class::String>(
|
||||
data == nullptr ? nullptr : std::make_shared<std::string>(data)
|
||||
)
|
||||
{}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
String(const T& str)
|
||||
: type::ObjectWrapper<std::string, __class::String>(std::make_shared<std::string>(str))
|
||||
{}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
String(T&& str)
|
||||
: type::ObjectWrapper<std::string, __class::String>(
|
||||
std::make_shared<std::string>(std::forward<std::string>(str))
|
||||
)
|
||||
{}
|
||||
|
||||
String(const std::shared_ptr<std::string>& ptr)
|
||||
: type::ObjectWrapper<std::string, __class::String>(ptr)
|
||||
{}
|
||||
|
||||
String(std::shared_ptr<std::string>&& ptr)
|
||||
: type::ObjectWrapper<std::string, __class::String>(std::forward<std::shared_ptr<std::string>>(ptr))
|
||||
{}
|
||||
|
||||
String(const String& other)
|
||||
: type::ObjectWrapper<std::string, __class::String>(other)
|
||||
{}
|
||||
|
||||
String(String&& other)
|
||||
: type::ObjectWrapper<std::string, __class::String>(std::forward<String>(other))
|
||||
{}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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*();
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
inline String& operator = (std::nullptr_t) {
|
||||
m_ptr.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String& operator = (const char* str) {
|
||||
m_ptr = base::StrBuffer::createFromCString(str);
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, char>::value, void>::type
|
||||
>
|
||||
inline String& operator = (const T* str) {
|
||||
m_ptr = std::make_shared<std::string>(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
inline String& operator = (const T& str) {
|
||||
m_ptr = std::make_shared<std::string>(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
inline String& operator = (T&& str) {
|
||||
m_ptr = std::make_shared<std::string>(std::forward<std::string>(str));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -115,46 +183,91 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String& operator = (String&& other){
|
||||
m_ptr = std::forward<std::shared_ptr<base::StrBuffer>>(other.m_ptr);
|
||||
inline String& operator = (String&& other) noexcept {
|
||||
m_ptr = std::move(other.m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator == (std::nullptr_t) const {
|
||||
/**
|
||||
* Case insensitive compare (ASCII only).
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
bool equalsCI_ASCII(const std::string& other);
|
||||
|
||||
/**
|
||||
* Case insensitive compare (ASCII only).
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
bool equalsCI_ASCII(const String& other);
|
||||
|
||||
/**
|
||||
* 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
|
||||
>
|
||||
inline bool operator == (T) const {
|
||||
return m_ptr.get() == nullptr;
|
||||
}
|
||||
|
||||
inline bool operator != (std::nullptr_t) const {
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
inline bool operator != (T) const {
|
||||
return m_ptr.get() != nullptr;
|
||||
}
|
||||
|
||||
inline bool operator == (const char* str) const {
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, char>::value, void>::type
|
||||
>
|
||||
inline bool operator == (const T* str) const {
|
||||
if(!m_ptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_ptr->getSize() != v_buff_size(std::strlen(str))) return false;
|
||||
return base::StrBuffer::equals(m_ptr->getData(), str, m_ptr->getSize());
|
||||
return *m_ptr == str;
|
||||
}
|
||||
|
||||
inline bool operator != (const char* str) const {
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, char>::value, void>::type
|
||||
>
|
||||
inline bool operator != (const T* str) const {
|
||||
return !operator == (str);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
inline bool operator == (const T& str) const {
|
||||
if(!m_ptr) return false;
|
||||
return *m_ptr == str;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::string>::value, void>::type
|
||||
>
|
||||
inline bool operator != (const T& str) const {
|
||||
return !operator == (str);
|
||||
}
|
||||
|
||||
inline bool operator == (const String &other) const {
|
||||
return base::StrBuffer::equals(m_ptr.get(), other.m_ptr.get());
|
||||
if(!m_ptr) return !other.m_ptr;
|
||||
if(!other.m_ptr) return false;
|
||||
return *m_ptr == *other.m_ptr;
|
||||
}
|
||||
|
||||
inline bool operator != (const String &other) const {
|
||||
return !operator == (other);
|
||||
}
|
||||
|
||||
inline explicit operator bool() const {
|
||||
return m_ptr.operator bool();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
String operator + (const char* a, const String& b);
|
||||
String operator + (const String& b, const char* a);
|
||||
String operator + (const String& a, const char* b);
|
||||
String operator + (const String& a, const String& b);
|
||||
|
||||
/**
|
||||
@ -232,7 +345,7 @@ public:
|
||||
inline operator TValueType() const {
|
||||
return *this->m_ptr;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -402,29 +515,29 @@ template<>
|
||||
struct ObjectWrapperByUnderlyingType <bool> {
|
||||
typedef Boolean ObjectWrapper;
|
||||
};
|
||||
|
||||
|
||||
namespace __class {
|
||||
|
||||
|
||||
class String {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Int8 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class UInt8 {
|
||||
@ -441,12 +554,12 @@ namespace __class {
|
||||
class Int16 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class UInt16 {
|
||||
@ -459,16 +572,16 @@ namespace __class {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Int32 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class UInt32 {
|
||||
@ -481,16 +594,16 @@ namespace __class {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Int64 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class UInt64 {
|
||||
@ -507,62 +620,53 @@ namespace __class {
|
||||
class Float32 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Float64 {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Boolean {
|
||||
public:
|
||||
static const ClassId CLASS_ID;
|
||||
|
||||
|
||||
static Type* getType(){
|
||||
static Type type(CLASS_ID, nullptr);
|
||||
return &type;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
namespace std {
|
||||
|
||||
|
||||
template<>
|
||||
struct hash<oatpp::data::mapping::type::String> {
|
||||
|
||||
|
||||
typedef oatpp::data::mapping::type::String argument_type;
|
||||
typedef v_uint64 result_type;
|
||||
|
||||
|
||||
result_type operator()(argument_type const& s) const noexcept {
|
||||
if(s.get() == nullptr) return 0;
|
||||
|
||||
p_char8 data = s->getData();
|
||||
result_type result = 0;
|
||||
for(v_buff_size i = 0; i < s->getSize(); i++) {
|
||||
v_char8 c = data[i] | 32;
|
||||
result = (31 * result) + c;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
return hash<std::string> {} (*s);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include <string>
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping { namespace type {
|
||||
|
||||
|
||||
class Type; // FWD
|
||||
|
||||
/**
|
||||
@ -90,6 +90,8 @@ namespace __class {
|
||||
|
||||
}
|
||||
|
||||
class Void; // FWD
|
||||
|
||||
/**
|
||||
* ObjectWrapper holds std::shared_ptr to object, object static type, plus object dynamic type information.
|
||||
* @tparam T - Object Type.
|
||||
@ -97,8 +99,10 @@ namespace __class {
|
||||
*/
|
||||
template <class T, class Clazz = __class::Void>
|
||||
class ObjectWrapper {
|
||||
friend Void;
|
||||
protected:
|
||||
std::shared_ptr<T> m_ptr;
|
||||
const Type* m_valueType;
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -114,41 +118,41 @@ public:
|
||||
|
||||
ObjectWrapper(const std::shared_ptr<T>& ptr)
|
||||
: m_ptr(ptr)
|
||||
, valueType(Class::getType())
|
||||
, m_valueType(Class::getType())
|
||||
{}
|
||||
|
||||
ObjectWrapper(const std::shared_ptr<T>& ptr, const Type* const type)
|
||||
: m_ptr(ptr)
|
||||
, valueType(type)
|
||||
, m_valueType(type)
|
||||
{}
|
||||
|
||||
ObjectWrapper(std::shared_ptr<T>&& ptr, const Type* const type)
|
||||
: m_ptr(std::move(ptr))
|
||||
, valueType(type)
|
||||
, m_valueType(type)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
ObjectWrapper()
|
||||
: valueType(Class::getType())
|
||||
: m_valueType(Class::getType())
|
||||
{}
|
||||
|
||||
ObjectWrapper(std::nullptr_t)
|
||||
: valueType(Class::getType())
|
||||
: m_valueType(Class::getType())
|
||||
{}
|
||||
|
||||
ObjectWrapper(const Type* const type)
|
||||
: valueType(type)
|
||||
: m_valueType(type)
|
||||
{}
|
||||
|
||||
ObjectWrapper(const ObjectWrapper& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
, valueType(other.valueType)
|
||||
, m_valueType(other.m_valueType)
|
||||
{}
|
||||
|
||||
ObjectWrapper(ObjectWrapper&& other)
|
||||
: m_ptr(std::move(other.m_ptr))
|
||||
, valueType(other.valueType)
|
||||
, m_valueType(other.m_valueType)
|
||||
{}
|
||||
|
||||
inline ObjectWrapper& operator=(const ObjectWrapper& other){
|
||||
@ -160,14 +164,10 @@ public:
|
||||
m_ptr = std::move(other.m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator ObjectWrapper<void>() const {
|
||||
return ObjectWrapper<void>(this->m_ptr, valueType);
|
||||
}
|
||||
|
||||
template<class Wrapper>
|
||||
Wrapper staticCast() const {
|
||||
return Wrapper(std::static_pointer_cast<typename Wrapper::ObjectType>(m_ptr), valueType);
|
||||
return Wrapper(std::static_pointer_cast<typename Wrapper::ObjectType>(m_ptr), m_valueType);
|
||||
}
|
||||
|
||||
inline T* operator->() const {
|
||||
@ -207,14 +207,97 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Value type information.
|
||||
* See &l:Type;.
|
||||
* Get value type
|
||||
* @return
|
||||
*/
|
||||
const Type* const valueType;
|
||||
const Type* getValueType() const {
|
||||
return m_valueType;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef ObjectWrapper<void, __class::Void> Void;
|
||||
class Void : public ObjectWrapper<void, __class::Void> {
|
||||
public:
|
||||
Void(const std::shared_ptr<void>& ptr, const type::Type* const valueType)
|
||||
: ObjectWrapper<void, __class::Void>(ptr, valueType)
|
||||
{}
|
||||
public:
|
||||
|
||||
Void() {}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
Void(T) {}
|
||||
|
||||
Void(const Type* const type)
|
||||
: ObjectWrapper<void, __class::Void>(type)
|
||||
{}
|
||||
|
||||
Void(const std::shared_ptr<void>& ptr)
|
||||
: type::ObjectWrapper<void, __class::Void>(ptr)
|
||||
{}
|
||||
|
||||
Void(std::shared_ptr<void>&& ptr)
|
||||
: type::ObjectWrapper<void, __class::Void>(std::forward<std::shared_ptr<void>>(ptr))
|
||||
{}
|
||||
|
||||
template<typename T, typename C>
|
||||
Void(const ObjectWrapper<T, C>& other)
|
||||
: type::ObjectWrapper<void, __class::Void>(other.getPtr(), other.getValueType())
|
||||
{}
|
||||
|
||||
template<typename T, typename C>
|
||||
Void(ObjectWrapper<T, C>&& other)
|
||||
: type::ObjectWrapper<void, __class::Void>(std::move(other.getPtr()), other.getValueType())
|
||||
{}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
inline Void& operator = (std::nullptr_t) {
|
||||
m_ptr.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename C>
|
||||
inline Void& operator = (const ObjectWrapper<T, C>& other){
|
||||
m_ptr = other.m_ptr;
|
||||
m_valueType = other.getValueType();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename C>
|
||||
inline Void& operator = (ObjectWrapper<T, C>&& other){
|
||||
m_ptr = std::move(other.m_ptr);
|
||||
m_valueType = other.getValueType();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
inline bool operator == (T) const {
|
||||
return m_ptr.get() == nullptr;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename enabled = typename std::enable_if<std::is_same<T, std::nullptr_t>::value, void>::type
|
||||
>
|
||||
inline bool operator != (T) const {
|
||||
return m_ptr.get() != nullptr;
|
||||
}
|
||||
|
||||
template<typename T, typename C>
|
||||
inline bool operator == (const ObjectWrapper<T, C> &other) const {
|
||||
return m_ptr.get() == other.get();
|
||||
}
|
||||
|
||||
template<typename T, typename C>
|
||||
inline bool operator != (const ObjectWrapper<T, C> &other) const {
|
||||
return m_ptr.get() != other.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ObjectWrapperByUnderlyingType {};
|
||||
|
@ -37,7 +37,7 @@ namespace oatpp { namespace data { namespace share {
|
||||
* Lazy String Map keeps keys, and values as memory label.
|
||||
* Once value is requested by user, the new memory block is allocated and value is copied to be stored permanently.
|
||||
* @tparam Key - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
|
||||
* &id:oatpp::data::share::StringKeyLabelCI_FAST;.
|
||||
* &id:oatpp::data::share::StringKeyLabelCI;.
|
||||
*/
|
||||
template<typename Key, typename MapType>
|
||||
class LazyStringMapTemplate {
|
||||
@ -242,8 +242,7 @@ public:
|
||||
|
||||
/**
|
||||
* Get value as a memory label.
|
||||
* @tparam T - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
|
||||
* &id:oatpp::data::share::StringKeyLabelCI_FAST;.
|
||||
* @tparam T - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;.
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@ -257,7 +256,7 @@ public:
|
||||
if(it != m_map.end()) {
|
||||
it->second.captureToOwnMemory();
|
||||
const auto& label = it->second;
|
||||
return T(label.getMemoryHandle(), label.getData(), label.getSize());
|
||||
return T(label.getMemoryHandle(), (const char*) label.getData(), label.getSize());
|
||||
}
|
||||
|
||||
return T(nullptr, nullptr, 0);
|
||||
@ -267,7 +266,7 @@ public:
|
||||
/**
|
||||
* Get value as a memory label without allocating memory for value.
|
||||
* @tparam T - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
|
||||
* * &id:oatpp::data::share::StringKeyLabelCI_FAST;.
|
||||
* * &id:oatpp::data::share::StringKeyLabelCI;.
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@ -280,7 +279,7 @@ public:
|
||||
|
||||
if(it != m_map.end()) {
|
||||
const auto& label = it->second;
|
||||
return T(label.getMemoryHandle(), label.getData(), label.getSize());
|
||||
return T(label.getMemoryHandle(), (const char*)label.getData(), label.getSize());
|
||||
}
|
||||
|
||||
return T(nullptr, nullptr, 0);
|
||||
|
@ -28,46 +28,34 @@
|
||||
|
||||
namespace oatpp { namespace data { namespace share {
|
||||
|
||||
MemoryLabel::MemoryLabel(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size)
|
||||
MemoryLabel::MemoryLabel(const std::shared_ptr<std::string>& memHandle, const void* data, v_buff_size size)
|
||||
: m_memoryHandle(memHandle)
|
||||
, m_data(data)
|
||||
, m_size(size)
|
||||
{}
|
||||
|
||||
StringKeyLabel::StringKeyLabel(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size)
|
||||
StringKeyLabel::StringKeyLabel(const std::shared_ptr<std::string>& memHandle, const char* data, v_buff_size size)
|
||||
: oatpp::data::share::MemoryLabel(memHandle, data, size)
|
||||
{}
|
||||
|
||||
StringKeyLabel::StringKeyLabel(const char* constText)
|
||||
: oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText))
|
||||
: oatpp::data::share::MemoryLabel(nullptr, constText, std::strlen(constText))
|
||||
{}
|
||||
|
||||
StringKeyLabel::StringKeyLabel(const String& str)
|
||||
: oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize())
|
||||
: oatpp::data::share::MemoryLabel(str.getPtr(), str->data(), str->size())
|
||||
{}
|
||||
|
||||
StringKeyLabelCI::StringKeyLabelCI(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size)
|
||||
StringKeyLabelCI::StringKeyLabelCI(const std::shared_ptr<std::string>& memHandle, const char* data, v_buff_size size)
|
||||
: oatpp::data::share::MemoryLabel(memHandle, data, size)
|
||||
{}
|
||||
|
||||
StringKeyLabelCI::StringKeyLabelCI(const char* constText)
|
||||
: oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText))
|
||||
: oatpp::data::share::MemoryLabel(nullptr, constText, std::strlen(constText))
|
||||
{}
|
||||
|
||||
StringKeyLabelCI::StringKeyLabelCI(const String& str)
|
||||
: oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize())
|
||||
{}
|
||||
|
||||
StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size)
|
||||
: oatpp::data::share::MemoryLabel(memHandle, data, size)
|
||||
{}
|
||||
|
||||
StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const char* constText)
|
||||
: oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText))
|
||||
{}
|
||||
|
||||
StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const String& str)
|
||||
: oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize())
|
||||
: oatpp::data::share::MemoryLabel(str.getPtr(), str->data(), str->size())
|
||||
{}
|
||||
|
||||
}}}
|
||||
|
@ -25,8 +25,10 @@
|
||||
#ifndef oatpp_data_share_MemoryLabel_hpp
|
||||
#define oatpp_data_share_MemoryLabel_hpp
|
||||
|
||||
#include "oatpp/core/base/StrBuffer.hpp"
|
||||
#include <memory>
|
||||
|
||||
#include "oatpp/core/data/mapping/type/Primitive.hpp"
|
||||
#include "oatpp/core/utils/String.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace share {
|
||||
|
||||
@ -39,8 +41,8 @@ class MemoryLabel {
|
||||
public:
|
||||
typedef oatpp::data::mapping::type::String String;
|
||||
protected:
|
||||
mutable std::shared_ptr<base::StrBuffer> m_memoryHandle;
|
||||
mutable p_char8 m_data;
|
||||
mutable std::shared_ptr<std::string> m_memoryHandle;
|
||||
mutable const void* m_data;
|
||||
v_buff_size m_size;
|
||||
public:
|
||||
|
||||
@ -64,9 +66,15 @@ public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param str
|
||||
* @param ptr
|
||||
*/
|
||||
MemoryLabel(const std::shared_ptr<base::StrBuffer>& str) : MemoryLabel(str, str->getData(), str->getSize()) {}
|
||||
MemoryLabel(const std::shared_ptr<std::string>& ptr) :
|
||||
MemoryLabel(
|
||||
ptr,
|
||||
ptr ? ptr->data() : nullptr,
|
||||
ptr ? (v_buff_size) ptr->size() : 0
|
||||
)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -74,13 +82,13 @@ public:
|
||||
* @param data - pointer to data.
|
||||
* @param size - size of the data in bytes.
|
||||
*/
|
||||
MemoryLabel(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size);
|
||||
MemoryLabel(const std::shared_ptr<std::string>& memHandle, const void* data, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Get pointer to labeled data.
|
||||
* @return - pointer to data.
|
||||
*/
|
||||
p_char8 getData() const {
|
||||
const void* getData() const {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
@ -94,9 +102,9 @@ public:
|
||||
|
||||
/**
|
||||
* Get memory handle which this memory label holds.
|
||||
* @return - `std::shared_ptr` to &id:oatpp::base::StrBuffer;.
|
||||
* @return - `std::shared_ptr` to `std::string`.
|
||||
*/
|
||||
std::shared_ptr<base::StrBuffer> getMemoryHandle() const {
|
||||
std::shared_ptr<std::string> getMemoryHandle() const {
|
||||
return m_memoryHandle;
|
||||
}
|
||||
|
||||
@ -104,32 +112,32 @@ public:
|
||||
* Capture data referenced by memory label to its own memory.
|
||||
*/
|
||||
void captureToOwnMemory() const {
|
||||
if(!m_memoryHandle || m_memoryHandle->getData() != m_data || m_memoryHandle->getSize() != m_size) {
|
||||
m_memoryHandle.reset(new base::StrBuffer(m_data, m_size, true));
|
||||
m_data = m_memoryHandle->getData();
|
||||
if(!m_memoryHandle || m_memoryHandle->data() != (const char*)m_data || m_memoryHandle->size() != m_size) {
|
||||
m_memoryHandle = std::make_shared<std::string>((const char*) m_data, m_size);
|
||||
m_data = (p_char8) m_memoryHandle->data();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if labeled data equals to data specified.
|
||||
* Data is compared using &id:oatpp::base::StrBuffer::equals;.
|
||||
* Data is compared using &id:oatpp::urils::String::compare;.
|
||||
* @param data - data to compare with labeled data.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
bool equals(const char* data) const {
|
||||
v_buff_size size = std::strlen(data);
|
||||
return m_size == size && base::StrBuffer::equals(m_data, data, m_size);
|
||||
auto len = data != nullptr ? std::strlen(data) : 0;
|
||||
return utils::String::compare(m_data, m_size, data, len) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if labeled data equals to data specified.
|
||||
* Data is compared using &id:oatpp::base::StrBuffer::equals;.
|
||||
* Data is compared using &id:oatpp::urils::String::compare;.
|
||||
* @param data - data to compare with labeled data.
|
||||
* @param size - data size.
|
||||
* @return - `true` if equals.
|
||||
*/
|
||||
bool equals(const void* data, v_buff_size size) const {
|
||||
return m_size == size && base::StrBuffer::equals(m_data, data, m_size);
|
||||
return utils::String::compare(m_data, m_size, data, size) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,7 +145,7 @@ public:
|
||||
* @return oatpp::String(data, size)
|
||||
*/
|
||||
String toString() const {
|
||||
return String((const char*) m_data, m_size, true);
|
||||
return String((const char*) m_data, m_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,8 +179,14 @@ public:
|
||||
StringKeyLabel() : MemoryLabel() {};
|
||||
|
||||
StringKeyLabel(std::nullptr_t) : MemoryLabel() {}
|
||||
|
||||
StringKeyLabel(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@ -185,10 +199,7 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != v_buff_size(std::strlen(str))) return false;
|
||||
return base::StrBuffer::equals(m_data, str, m_size);
|
||||
return equals(str);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str) const {
|
||||
@ -198,8 +209,7 @@ public:
|
||||
inline bool operator==(const String& str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != str->getSize()) return false;
|
||||
return base::StrBuffer::equals(m_data, str->getData(), m_size);
|
||||
return equals(str->data(), str->size());
|
||||
}
|
||||
|
||||
inline bool operator!=(const String& str) const {
|
||||
@ -207,19 +217,19 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const StringKeyLabel &other) const {
|
||||
return m_size == other.m_size && base::StrBuffer::equals(m_data, other.m_data, m_size);
|
||||
return utils::String::compare(m_data, m_size, other.m_data, other.m_size) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const StringKeyLabel &other) const {
|
||||
return !(m_size == other.m_size && base::StrBuffer::equals(m_data, other.m_data, m_size));
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
inline bool operator < (const StringKeyLabel &other) const {
|
||||
return base::StrBuffer::compare(m_data, m_size, other.m_data, other.m_size) < 0;
|
||||
return utils::String::compare(m_data, m_size, other.m_data, other.m_size) < 0;
|
||||
}
|
||||
|
||||
inline bool operator > (const StringKeyLabel &other) const {
|
||||
return base::StrBuffer::compare(m_data, m_size, other.m_data, other.m_size) > 0;
|
||||
return utils::String::compare(m_data, m_size, other.m_data, other.m_size) > 0;
|
||||
}
|
||||
|
||||
};
|
||||
@ -234,7 +244,9 @@ public:
|
||||
|
||||
StringKeyLabelCI(std::nullptr_t) : MemoryLabel() {}
|
||||
|
||||
StringKeyLabelCI(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size);
|
||||
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);
|
||||
|
||||
@ -247,10 +259,8 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != v_buff_size(std::strlen(str))) return false;
|
||||
return base::StrBuffer::equalsCI(m_data, str, m_size);
|
||||
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 {
|
||||
@ -260,8 +270,7 @@ public:
|
||||
inline bool operator==(const String& str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != str->getSize()) return false;
|
||||
return base::StrBuffer::equalsCI(m_data, str->getData(), m_size);
|
||||
return utils::String::compareCI_ASCII(m_data, m_size, str->data(), str->size()) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const String& str) const {
|
||||
@ -269,86 +278,22 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const StringKeyLabelCI &other) const {
|
||||
return m_size == other.m_size && base::StrBuffer::equalsCI(m_data, other.m_data, m_size);
|
||||
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const StringKeyLabelCI &other) const {
|
||||
return !(m_size == other.m_size && base::StrBuffer::equalsCI(m_data, other.m_data, m_size));
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
inline bool operator < (const StringKeyLabelCI &other) const {
|
||||
return base::StrBuffer::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 base::StrBuffer::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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* MemoryLabel which can be used as a case-insensitive-fast key in unordered_map.
|
||||
* CI_FAST - is appropriate for strings consisting of [a..z] + [A..Z] only.
|
||||
* for other symbols undefined collisions may occur.
|
||||
*/
|
||||
class StringKeyLabelCI_FAST : public MemoryLabel {
|
||||
public:
|
||||
|
||||
StringKeyLabelCI_FAST() : MemoryLabel() {};
|
||||
|
||||
StringKeyLabelCI_FAST(std::nullptr_t) : MemoryLabel() {}
|
||||
|
||||
StringKeyLabelCI_FAST(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_buff_size size);
|
||||
StringKeyLabelCI_FAST(const char* constText);
|
||||
StringKeyLabelCI_FAST(const String& str);
|
||||
|
||||
inline bool operator==(std::nullptr_t) const {
|
||||
return m_data == nullptr;
|
||||
}
|
||||
|
||||
inline bool operator!=(std::nullptr_t) const {
|
||||
return m_data != nullptr;
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != v_buff_size(std::strlen(str))) return false;
|
||||
return base::StrBuffer::equalsCI_FAST(m_data, str, m_size);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str) const {
|
||||
return !operator==(str);
|
||||
}
|
||||
|
||||
inline bool operator==(const String& str) const {
|
||||
if(m_data == nullptr) return str == nullptr;
|
||||
if(str == nullptr) return false;
|
||||
if(m_size != str->getSize()) return false;
|
||||
return base::StrBuffer::equalsCI_FAST(m_data, str->getData(), m_size);
|
||||
}
|
||||
|
||||
inline bool operator!=(const String& str) const {
|
||||
return !operator==(str);
|
||||
}
|
||||
|
||||
inline bool operator==(const StringKeyLabelCI_FAST &other) const {
|
||||
return m_size == other.m_size && base::StrBuffer::equalsCI_FAST(m_data, other.m_data, m_size);
|
||||
}
|
||||
|
||||
inline bool operator!=(const StringKeyLabelCI_FAST &other) const {
|
||||
return !(m_size == other.m_size && base::StrBuffer::equalsCI_FAST(m_data, other.m_data, m_size));
|
||||
}
|
||||
|
||||
inline bool operator < (const StringKeyLabelCI_FAST &other) const {
|
||||
return base::StrBuffer::compareCI_FAST(m_data, m_size, other.m_data, other.m_size) < 0;
|
||||
}
|
||||
|
||||
inline bool operator > (const StringKeyLabelCI_FAST &other) const {
|
||||
return base::StrBuffer::compareCI_FAST(m_data, m_size, other.m_data, other.m_size) > 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
@ -362,7 +307,7 @@ namespace std {
|
||||
|
||||
result_type operator()(oatpp::data::share::StringKeyLabel const& s) const noexcept {
|
||||
|
||||
p_char8 data = 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];
|
||||
@ -382,27 +327,7 @@ namespace std {
|
||||
|
||||
result_type operator()(oatpp::data::share::StringKeyLabelCI const& s) const noexcept {
|
||||
|
||||
p_char8 data = s.getData();
|
||||
result_type result = 0;
|
||||
for(v_buff_size i = 0; i < s.getSize(); i++) {
|
||||
v_char8 c = data[i] | 32;
|
||||
result = (31 * result) + c;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<oatpp::data::share::StringKeyLabelCI_FAST> {
|
||||
|
||||
typedef oatpp::data::share::StringKeyLabelCI_FAST argument_type;
|
||||
typedef v_uint64 result_type;
|
||||
|
||||
result_type operator()(oatpp::data::share::StringKeyLabelCI_FAST const& s) const noexcept {
|
||||
|
||||
p_char8 data = 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;
|
||||
|
@ -76,7 +76,7 @@ StringTemplate::StringTemplate(const oatpp::String& text, std::vector<Variable>&
|
||||
throw std::runtime_error("[oatpp::data::share::StringTemplate::StringTemplate()]: Error. The template variable can't have a negative size.");
|
||||
}
|
||||
|
||||
if(var.posEnd >= m_text->getSize()) {
|
||||
if(var.posEnd >= m_text->size()) {
|
||||
throw std::runtime_error("[oatpp::data::share::StringTemplate::StringTemplate()]: Error. The template variable can't out-bound the template text.");
|
||||
}
|
||||
}
|
||||
@ -92,21 +92,21 @@ void StringTemplate::format(stream::ConsistentOutputStream* stream, ValueProvide
|
||||
|
||||
if(!value) {
|
||||
throw std::runtime_error("[oatpp::data::share::StringTemplate::format()]: "
|
||||
"Error. No value provided for the parameter name=" + var.name->std_str());
|
||||
"Error. No value provided for the parameter name=" + *var.name);
|
||||
}
|
||||
|
||||
if(prevPos < var.posStart) {
|
||||
stream->writeSimple(m_text->getData() + prevPos, var.posStart - prevPos);
|
||||
stream->writeSimple(m_text->data() + prevPos, var.posStart - prevPos);
|
||||
}
|
||||
|
||||
stream->writeSimple(value->getData(), value->getSize());
|
||||
stream->writeSimple(value->data(), value->size());
|
||||
|
||||
prevPos = var.posEnd + 1;
|
||||
|
||||
}
|
||||
|
||||
if(prevPos < m_text->getSize()) {
|
||||
stream->writeSimple(m_text->getData() + prevPos, m_text->getSize() - prevPos);
|
||||
if(prevPos < m_text->size()) {
|
||||
stream->writeSimple(m_text->data() + prevPos, m_text->size() - prevPos);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -117,14 +117,14 @@ void BufferOutputStream::setCurrentPosition(v_buff_size position) {
|
||||
}
|
||||
|
||||
oatpp::String BufferOutputStream::toString() {
|
||||
return oatpp::String((const char*)m_data, m_position, true);
|
||||
return oatpp::String((const char*) m_data, m_position);
|
||||
}
|
||||
|
||||
oatpp::String BufferOutputStream::getSubstring(v_buff_size pos, v_buff_size count) {
|
||||
if(pos + count <= m_position) {
|
||||
return oatpp::String((const char *) (m_data + pos), count, true);
|
||||
return oatpp::String((const char *) (m_data + pos), count);
|
||||
} else {
|
||||
return oatpp::String((const char *) (m_data + pos), m_position - pos, true);
|
||||
return oatpp::String((const char *) (m_data + pos), m_position - pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,19 +167,19 @@ oatpp::async::CoroutineStarter BufferOutputStream::flushToStreamAsync(const std:
|
||||
|
||||
data::stream::DefaultInitializedContext BufferInputStream::DEFAULT_CONTEXT(data::stream::StreamType::STREAM_FINITE);
|
||||
|
||||
BufferInputStream::BufferInputStream(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_buff_size size)
|
||||
BufferInputStream::BufferInputStream(const std::shared_ptr<std::string>& memoryHandle, const void* data, v_buff_size size)
|
||||
: m_memoryHandle(memoryHandle)
|
||||
, m_data(data)
|
||||
, m_data((p_char8) data)
|
||||
, m_size(size)
|
||||
, m_position(0)
|
||||
, m_ioMode(IOMode::ASYNCHRONOUS)
|
||||
{}
|
||||
|
||||
BufferInputStream::BufferInputStream(const oatpp::String& data)
|
||||
: BufferInputStream(data.getPtr(), data->getData(), data->getSize())
|
||||
: BufferInputStream(data.getPtr(), (p_char8) data->data(), data->size())
|
||||
{}
|
||||
|
||||
void BufferInputStream::reset(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_buff_size size) {
|
||||
void BufferInputStream::reset(const std::shared_ptr<std::string>& memoryHandle, p_char8 data, v_buff_size size) {
|
||||
m_memoryHandle = memoryHandle;
|
||||
m_data = data;
|
||||
m_size = size;
|
||||
@ -218,7 +218,7 @@ Context& BufferInputStream::getInputStreamContext() {
|
||||
return DEFAULT_CONTEXT;
|
||||
}
|
||||
|
||||
std::shared_ptr<base::StrBuffer> BufferInputStream::getDataMemoryHandle() {
|
||||
std::shared_ptr<std::string> BufferInputStream::getDataMemoryHandle() {
|
||||
return m_memoryHandle;
|
||||
}
|
||||
|
||||
@ -238,4 +238,27 @@ void BufferInputStream::setCurrentPosition(v_buff_size position) {
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
v_io_size BufferInputStream::peek(void *data, v_buff_size count, async::Action &action) {
|
||||
(void) action;
|
||||
|
||||
v_buff_size desiredAmount = count;
|
||||
if(desiredAmount > m_size - m_position) {
|
||||
desiredAmount = m_size - m_position;
|
||||
}
|
||||
std::memcpy(data, &m_data[m_position], desiredAmount);
|
||||
return desiredAmount;
|
||||
}
|
||||
|
||||
v_io_size BufferInputStream::availableToRead() const {
|
||||
return m_size - m_position;
|
||||
}
|
||||
|
||||
v_io_size BufferInputStream::commitReadOffset(v_buff_size count) {
|
||||
if(count > m_size - m_position) {
|
||||
count = m_size - m_position;
|
||||
}
|
||||
m_position += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -146,11 +146,11 @@ public:
|
||||
/**
|
||||
* BufferInputStream
|
||||
*/
|
||||
class BufferInputStream : public InputStream {
|
||||
class BufferInputStream : public BufferedInputStream {
|
||||
public:
|
||||
static data::stream::DefaultInitializedContext DEFAULT_CONTEXT;
|
||||
private:
|
||||
std::shared_ptr<base::StrBuffer> m_memoryHandle;
|
||||
std::shared_ptr<std::string> m_memoryHandle;
|
||||
p_char8 m_data;
|
||||
v_buff_size m_size;
|
||||
v_buff_size m_position;
|
||||
@ -163,7 +163,7 @@ public:
|
||||
* @param data - pointer to buffer data.
|
||||
* @param size - size of the buffer.
|
||||
*/
|
||||
BufferInputStream(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_buff_size size);
|
||||
BufferInputStream(const std::shared_ptr<std::string>& memoryHandle, const void* data, v_buff_size size);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -177,7 +177,7 @@ public:
|
||||
* @param data - pointer to buffer data.
|
||||
* @param size - size of the buffer.
|
||||
*/
|
||||
void reset(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_buff_size size);
|
||||
void reset(const std::shared_ptr<std::string>& memoryHandle, p_char8 data, v_buff_size size);
|
||||
|
||||
|
||||
/**
|
||||
@ -219,7 +219,7 @@ public:
|
||||
* Get data memory handle.
|
||||
* @return - data memory handle.
|
||||
*/
|
||||
std::shared_ptr<base::StrBuffer> getDataMemoryHandle();
|
||||
std::shared_ptr<std::string> getDataMemoryHandle();
|
||||
|
||||
/**
|
||||
* Get pointer to data.
|
||||
@ -245,6 +245,26 @@ public:
|
||||
*/
|
||||
void setCurrentPosition(v_buff_size position);
|
||||
|
||||
/**
|
||||
* Peek up to count of bytes int he buffer
|
||||
* @param data
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size peek(void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
/**
|
||||
* Amount of bytes currently available to read from buffer.
|
||||
* @return &id:oatpp::v_io_size;.
|
||||
*/
|
||||
v_io_size availableToRead() const override;
|
||||
|
||||
/**
|
||||
* Commit read offset
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size commitReadOffset(v_buff_size count) override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -165,8 +165,8 @@ Context& ChunkedBuffer::getOutputStreamContext() {
|
||||
}
|
||||
|
||||
v_io_size ChunkedBuffer::readSubstring(void *buffer,
|
||||
v_buff_size pos,
|
||||
v_buff_size count)
|
||||
v_buff_size pos,
|
||||
v_buff_size count)
|
||||
{
|
||||
|
||||
if(pos < 0 || pos >= m_size){
|
||||
@ -215,7 +215,7 @@ v_io_size ChunkedBuffer::readSubstring(void *buffer,
|
||||
|
||||
oatpp::String ChunkedBuffer::getSubstring(v_buff_size pos, v_buff_size count){
|
||||
auto str = oatpp::String((v_int32) count);
|
||||
readSubstring(str->getData(), pos, count);
|
||||
readSubstring((p_char8)str->data(), pos, count);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -303,15 +303,13 @@ oatpp::async::CoroutineStarter ChunkedBuffer::flushToStreamAsync(const std::shar
|
||||
}
|
||||
|
||||
std::shared_ptr<ChunkedBuffer::Chunks> ChunkedBuffer::getChunks() {
|
||||
auto chunks = Chunks::createShared();
|
||||
auto chunks = std::make_shared<Chunks>();
|
||||
auto curr = m_firstEntry;
|
||||
v_int32 count = 0;
|
||||
while (curr != nullptr) {
|
||||
if(curr->next != nullptr){
|
||||
chunks->pushBack(Chunk::createShared(curr->chunk, CHUNK_ENTRY_SIZE));
|
||||
} else {
|
||||
chunks->pushBack(Chunk::createShared(curr->chunk, m_size - CHUNK_ENTRY_SIZE * count));
|
||||
}
|
||||
chunks->push_back(Chunk::createShared(curr->chunk, curr->next
|
||||
? CHUNK_ENTRY_SIZE
|
||||
: m_size - CHUNK_ENTRY_SIZE * count));
|
||||
++count;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
@ -25,9 +25,10 @@
|
||||
#ifndef oatpp_data_stream_ChunkedBuffer_hpp
|
||||
#define oatpp_data_stream_ChunkedBuffer_hpp
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Stream.hpp"
|
||||
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
#include "oatpp/core/async/Coroutine.hpp"
|
||||
|
||||
namespace oatpp { namespace data{ namespace stream {
|
||||
@ -99,7 +100,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
typedef oatpp::collection::LinkedList<std::shared_ptr<Chunk>> Chunks;
|
||||
typedef std::list<std::shared_ptr<Chunk>> Chunks;
|
||||
private:
|
||||
|
||||
v_buff_size m_size;
|
||||
|
136
src/oatpp/core/data/stream/FIFOStream.cpp
Normal file
136
src/oatpp/core/data/stream/FIFOStream.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Benedikt-Alexander Mokroß <github@bamkrs.de>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "FIFOStream.hpp"
|
||||
#include "oatpp/core/utils/Binary.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace stream {
|
||||
|
||||
data::stream::DefaultInitializedContext FIFOInputStream::DEFAULT_CONTEXT(data::stream::StreamType::STREAM_FINITE);
|
||||
|
||||
FIFOInputStream::FIFOInputStream(v_buff_size initialSize)
|
||||
: m_memoryHandle(std::make_shared<std::string>(initialSize, (char)0))
|
||||
, m_fifo(std::make_shared<data::buffer::FIFOBuffer>((void*)m_memoryHandle->data(), m_memoryHandle->size(), 0, 0, false))
|
||||
, m_maxCapacity(-1) {
|
||||
|
||||
}
|
||||
|
||||
void FIFOInputStream::reset() {
|
||||
m_fifo->setBufferPosition(0, 0, false);
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::read(void *data, v_buff_size count, async::Action& action) {
|
||||
(void) action;
|
||||
return m_fifo->read(data, count);
|
||||
}
|
||||
|
||||
void FIFOInputStream::setInputStreamIOMode(IOMode ioMode) {
|
||||
m_ioMode = ioMode;
|
||||
}
|
||||
|
||||
IOMode FIFOInputStream::getInputStreamIOMode() {
|
||||
return m_ioMode;
|
||||
}
|
||||
|
||||
Context& FIFOInputStream::getInputStreamContext() {
|
||||
return DEFAULT_CONTEXT;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::string> FIFOInputStream::getDataMemoryHandle() {
|
||||
return m_memoryHandle;
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::write(const void *data, v_buff_size count, async::Action &action) {
|
||||
(void) action;
|
||||
reserveBytesUpfront(count);
|
||||
return m_fifo->write(data, count);
|
||||
}
|
||||
|
||||
void FIFOInputStream::reserveBytesUpfront(v_buff_size count) {
|
||||
|
||||
v_buff_size capacityNeeded = availableToRead() + count;
|
||||
|
||||
if(capacityNeeded > m_fifo->getBufferSize()) {
|
||||
|
||||
v_buff_size newCapacity = utils::Binary::nextP2(capacityNeeded);
|
||||
|
||||
if(newCapacity < 0 || (m_maxCapacity > 0 && newCapacity > m_maxCapacity)) {
|
||||
newCapacity = m_maxCapacity;
|
||||
}
|
||||
|
||||
if(newCapacity < capacityNeeded) {
|
||||
throw std::runtime_error("[oatpp::data::stream::BufferOutputStream::reserveBytesUpfront()]: Error. Unable to allocate requested memory.");
|
||||
}
|
||||
|
||||
// ToDo: In-Memory-Resize
|
||||
auto newHandle = std::make_shared<std::string>(newCapacity, (char)0);
|
||||
v_io_size oldSize = m_fifo->availableToRead();
|
||||
m_fifo->read((void*)newHandle->data(), oldSize);
|
||||
auto newFifo = std::make_shared<data::buffer::FIFOBuffer>((void*)newHandle->data(), newHandle->size(), 0, oldSize, oldSize > 0);
|
||||
m_memoryHandle = newHandle;
|
||||
m_fifo = newFifo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::readAndWriteToStream(data::stream::OutputStream *stream,
|
||||
v_buff_size count,
|
||||
async::Action &action) {
|
||||
return m_fifo->readAndWriteToStream(stream, count, action);
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::readFromStreamAndWrite(data::stream::InputStream *stream,
|
||||
v_buff_size count,
|
||||
async::Action &action) {
|
||||
reserveBytesUpfront(count);
|
||||
return m_fifo->readFromStreamAndWrite(stream, count, action);
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::flushToStream(data::stream::OutputStream *stream) {
|
||||
return m_fifo->flushToStream(stream);
|
||||
}
|
||||
|
||||
async::CoroutineStarter FIFOInputStream::flushToStreamAsync(const std::shared_ptr<data::stream::OutputStream> &stream) {
|
||||
return m_fifo->flushToStreamAsync(stream);
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::availableToWrite() {
|
||||
return m_fifo->availableToWrite();
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::peek(void *data, v_buff_size count, async::Action &action) {
|
||||
(void) action;
|
||||
return m_fifo->peek(data, count);
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::availableToRead() const {
|
||||
return m_fifo->availableToRead();
|
||||
}
|
||||
|
||||
v_io_size FIFOInputStream::commitReadOffset(v_buff_size count) {
|
||||
return m_fifo->commitReadOffset(count);
|
||||
}
|
||||
|
||||
}}}
|
175
src/oatpp/core/data/stream/FIFOStream.hpp
Normal file
175
src/oatpp/core/data/stream/FIFOStream.hpp
Normal file
@ -0,0 +1,175 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Benedikt-Alexander Mokroß <github@bamkrs.de>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_data_stream_FIFOStream_hpp
|
||||
#define oatpp_data_stream_FIFOStream_hpp
|
||||
|
||||
#include "Stream.hpp"
|
||||
#include "oatpp/core/data/buffer/FIFOBuffer.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace stream {
|
||||
|
||||
|
||||
/**
|
||||
* FIFOInputStream
|
||||
*/
|
||||
class FIFOInputStream : public BufferedInputStream, public WriteCallback {
|
||||
public:
|
||||
static data::stream::DefaultInitializedContext DEFAULT_CONTEXT;
|
||||
private:
|
||||
std::shared_ptr<std::string> m_memoryHandle;
|
||||
std::shared_ptr<data::buffer::FIFOBuffer> m_fifo;
|
||||
v_buff_size m_maxCapacity;
|
||||
IOMode m_ioMode;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param data - buffer.
|
||||
*/
|
||||
FIFOInputStream(v_buff_size initialSize = 4096);
|
||||
|
||||
static std::shared_ptr<FIFOInputStream> createShared(v_buff_size initialSize = 4096) {
|
||||
return std::make_shared<FIFOInputStream>(initialSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards all data in the buffer and resets it to an empty state
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Read data from stream. <br>
|
||||
* It is a legal case if return result < count. Caller should handle this!
|
||||
* *Calls to this method are always NON-BLOCKING*
|
||||
* @param data - buffer to read data to.
|
||||
* @param count - size of the buffer.
|
||||
* @param action - async specific action. If action is NOT &id:oatpp::async::Action::TYPE_NONE;, then
|
||||
* caller MUST return this action on coroutine iteration.
|
||||
* @return - actual number of bytes read. 0 - designates end of the buffer.
|
||||
*/
|
||||
v_io_size read(void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
/**
|
||||
* Set stream I/O mode.
|
||||
* @throws
|
||||
*/
|
||||
void setInputStreamIOMode(IOMode ioMode) override;
|
||||
|
||||
/**
|
||||
* Get stream I/O mode.
|
||||
* @return
|
||||
*/
|
||||
IOMode getInputStreamIOMode() override;
|
||||
|
||||
/**
|
||||
* Get stream context.
|
||||
* @return
|
||||
*/
|
||||
Context& getInputStreamContext() override;
|
||||
|
||||
/**
|
||||
* Get data memory handle.
|
||||
* @return - data memory handle.
|
||||
*/
|
||||
std::shared_ptr<std::string> getDataMemoryHandle();
|
||||
|
||||
/**
|
||||
* Write operation callback.
|
||||
* @param data - pointer to data.
|
||||
* @param count - size of the data in bytes.
|
||||
* @param action - async specific action. If action is NOT &id:oatpp::async::Action::TYPE_NONE;, then
|
||||
* caller MUST return this action on coroutine iteration.
|
||||
* @return - actual number of bytes written. 0 - to indicate end-of-file.
|
||||
*/
|
||||
v_io_size write(const void *data, v_buff_size count, async::Action &action) override;
|
||||
|
||||
/**
|
||||
* Peek up to count of bytes int he buffer
|
||||
* @param data
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size peek(void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
/**
|
||||
* Amount of bytes currently available to read from buffer.
|
||||
* @return &id:oatpp::v_io_size;.
|
||||
*/
|
||||
v_io_size availableToRead() const override;
|
||||
|
||||
/**
|
||||
* Commit read offset
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size commitReadOffset(v_buff_size count) override;
|
||||
|
||||
/**
|
||||
* Reserve bytes for future writes. Check &id:oatpp::data::stream::FIFOStream::availableToWrite for the capacity.
|
||||
*/
|
||||
void reserveBytesUpfront(v_buff_size count);
|
||||
|
||||
/**
|
||||
* call read and then write bytes read to output stream
|
||||
* @param stream
|
||||
* @param count
|
||||
* @param action
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
v_io_size readAndWriteToStream(data::stream::OutputStream* stream, v_buff_size count, async::Action& action);
|
||||
|
||||
/**
|
||||
* call stream.read() and then write bytes read to buffer
|
||||
* @param stream
|
||||
* @param count
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
v_io_size readFromStreamAndWrite(data::stream::InputStream* stream, v_buff_size count, async::Action& action);
|
||||
|
||||
/**
|
||||
* flush all availableToRead bytes to stream
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
v_io_size flushToStream(data::stream::OutputStream* stream);
|
||||
|
||||
/**
|
||||
* flush all availableToRead bytes to stream in asynchronous manner
|
||||
* @param stream - &id:data::stream::OutputStream;.
|
||||
* @return - &id:async::CoroutineStarter;.
|
||||
*/
|
||||
async::CoroutineStarter flushToStreamAsync(const std::shared_ptr<data::stream::OutputStream>& stream);
|
||||
|
||||
/**
|
||||
* Amount of buffer space currently available for data writes.
|
||||
* @return &id:oatpp::v_io_size;.
|
||||
*/
|
||||
v_io_size availableToWrite();
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // oatpp_data_stream_FIFOStream_hpp
|
@ -727,7 +727,11 @@ async::CoroutineStarter transferAsync(const base::ObjectHandle<ReadCallback>& re
|
||||
switch(res) {
|
||||
|
||||
case IOError::BROKEN_PIPE:
|
||||
return error<AsyncTransferError>("[oatpp::data::stream::transferAsync]: Error. ReadCallback. BROKEN_PIPE.");
|
||||
if(m_transferSize > 0) {
|
||||
return error<AsyncTransferError>("[oatpp::data::stream::transferAsync]: Error. ReadCallback. BROKEN_PIPE.");
|
||||
}
|
||||
m_inData.set(nullptr, 0);
|
||||
break;
|
||||
|
||||
case IOError::ZERO_VALUE:
|
||||
m_inData.set(nullptr, 0);
|
||||
@ -746,10 +750,13 @@ async::CoroutineStarter transferAsync(const base::ObjectHandle<ReadCallback>& re
|
||||
return repeat();
|
||||
|
||||
default:
|
||||
if(!action.isNone()) {
|
||||
return action;
|
||||
if(m_transferSize > 0) {
|
||||
if (!action.isNone()) {
|
||||
return action;
|
||||
}
|
||||
return error<AsyncTransferError>("[oatpp::data::stream::transferAsync]: Error. ReadCallback. Unknown IO error.");
|
||||
}
|
||||
return error<AsyncTransferError>("[oatpp::data::stream::transferAsync]: Error. ReadCallback. Unknown IO error.");
|
||||
m_inData.set(nullptr, 0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ public:
|
||||
* @return - actual number of bytes written. &id:oatpp::v_io_size;.
|
||||
*/
|
||||
v_io_size writeSimple(const oatpp::String& str){
|
||||
return writeSimple(str->getData(), str->getSize());
|
||||
return writeSimple(str->data(), str->size());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,6 +350,38 @@ public:
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffered Input Stream
|
||||
*/
|
||||
class BufferedInputStream : public InputStream {
|
||||
public:
|
||||
/**
|
||||
* Default virtual destructor.
|
||||
*/
|
||||
virtual ~BufferedInputStream() = default;
|
||||
|
||||
/**
|
||||
* Peek up to count of bytes int he buffer
|
||||
* @param data
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
virtual v_io_size peek(void *data, v_buff_size count, async::Action& action) = 0;
|
||||
|
||||
/**
|
||||
* Amount of bytes currently available to read from buffer.
|
||||
* @return &id:oatpp::v_io_size;.
|
||||
*/
|
||||
virtual v_io_size availableToRead() const = 0;
|
||||
|
||||
/**
|
||||
* Commit read offset
|
||||
* @param count
|
||||
* @return [1..count], IOErrors.
|
||||
*/
|
||||
virtual v_io_size commitReadOffset(v_buff_size count) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O Stream.
|
||||
*/
|
||||
|
@ -101,5 +101,9 @@ oatpp::data::stream::IOMode InputStreamBufferedProxy::getInputStreamIOMode() {
|
||||
Context& InputStreamBufferedProxy::getInputStreamContext() {
|
||||
return m_inputStream->getInputStreamContext();
|
||||
}
|
||||
|
||||
|
||||
v_io_size InputStreamBufferedProxy::availableToRead() const {
|
||||
return m_buffer.availableToRead();
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
const oatpp::data::share::MemoryLabel& memoryLabel)
|
||||
: m_outputStream(outputStream)
|
||||
, m_memoryLabel(memoryLabel)
|
||||
, m_buffer(memoryLabel.getData(), memoryLabel.getSize())
|
||||
, m_buffer((void *) memoryLabel.getData(), memoryLabel.getSize())
|
||||
{}
|
||||
public:
|
||||
|
||||
@ -82,7 +82,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class InputStreamBufferedProxy : public oatpp::base::Countable, public InputStream {
|
||||
class InputStreamBufferedProxy : public oatpp::base::Countable, public BufferedInputStream {
|
||||
public:
|
||||
OBJECT_POOL(InputStreamBufferedProxy_Pool, InputStreamBufferedProxy, 32)
|
||||
SHARED_OBJECT_POOL(Shared_InputStreamBufferedProxy_Pool, InputStreamBufferedProxy, 32)
|
||||
@ -98,7 +98,7 @@ public:
|
||||
bool bufferCanRead)
|
||||
: m_inputStream(inputStream)
|
||||
, m_memoryLabel(memoryLabel)
|
||||
, m_buffer(memoryLabel.getData(), memoryLabel.getSize(), bufferReadPosition, bufferWritePosition, bufferCanRead)
|
||||
, m_buffer((void*) memoryLabel.getData(), memoryLabel.getSize(), bufferReadPosition, bufferWritePosition, bufferCanRead)
|
||||
{}
|
||||
public:
|
||||
|
||||
@ -119,9 +119,11 @@ public:
|
||||
|
||||
v_io_size read(void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
v_io_size peek(void *data, v_buff_size count, async::Action& action);
|
||||
v_io_size peek(void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
v_io_size commitReadOffset(v_buff_size count);
|
||||
v_io_size commitReadOffset(v_buff_size count) override;
|
||||
|
||||
v_io_size availableToRead() const override;
|
||||
|
||||
/**
|
||||
* Set InputStream I/O mode.
|
||||
|
@ -54,7 +54,7 @@ namespace oatpp { namespace parser {
|
||||
m_end = m_caret->m_pos;
|
||||
}
|
||||
|
||||
p_char8 Caret::Label::getData(){
|
||||
const char* Caret::Label::getData(){
|
||||
return &m_caret->m_data[m_start];
|
||||
}
|
||||
|
||||
@ -73,16 +73,12 @@ namespace oatpp { namespace parser {
|
||||
return m_end;
|
||||
};
|
||||
|
||||
oatpp::String Caret::Label::toString(bool saveAsOwnData){
|
||||
oatpp::String Caret::Label::toString(){
|
||||
v_buff_size end = m_end;
|
||||
if(end == -1){
|
||||
end = m_caret->m_pos;
|
||||
}
|
||||
return oatpp::String((const char*)&m_caret->m_data[m_start], end - m_start, saveAsOwnData);
|
||||
}
|
||||
|
||||
oatpp::String Caret::Label::toString(){
|
||||
return toString(true);
|
||||
return oatpp::String((const char*)&m_caret->m_data[m_start], end - m_start);
|
||||
}
|
||||
|
||||
std::string Caret::Label::std_str(){
|
||||
@ -129,10 +125,10 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
// Caret
|
||||
|
||||
Caret::Caret(const char* text)
|
||||
: Caret((p_char8)text, std::strlen(text))
|
||||
: Caret(text, std::strlen(text))
|
||||
{}
|
||||
|
||||
Caret::Caret(p_char8 parseData, v_buff_size dataSize)
|
||||
Caret::Caret(const char* parseData, v_buff_size dataSize)
|
||||
: m_data(parseData)
|
||||
, m_size(dataSize)
|
||||
, m_pos(0)
|
||||
@ -141,7 +137,7 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
{}
|
||||
|
||||
Caret::Caret(const oatpp::String& str)
|
||||
: Caret(str->getData(), str->getSize())
|
||||
: Caret(str->data(), str->size())
|
||||
{
|
||||
m_dataMemoryHandle = str.getPtr();
|
||||
}
|
||||
@ -150,22 +146,22 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
return std::make_shared<Caret>(text);
|
||||
}
|
||||
|
||||
std::shared_ptr<Caret> Caret::createShared(p_char8 parseData, v_buff_size dataSize){
|
||||
std::shared_ptr<Caret> Caret::createShared(const char* parseData, v_buff_size dataSize){
|
||||
return std::make_shared<Caret>(parseData, dataSize);
|
||||
}
|
||||
|
||||
std::shared_ptr<Caret> Caret::createShared(const oatpp::String& str){
|
||||
return std::make_shared<Caret>(str->getData(), str->getSize());
|
||||
return std::make_shared<Caret>(str->data(), str->size());
|
||||
}
|
||||
|
||||
Caret::~Caret(){
|
||||
}
|
||||
|
||||
p_char8 Caret::getData(){
|
||||
const char* Caret::getData(){
|
||||
return m_data;
|
||||
}
|
||||
|
||||
p_char8 Caret::getCurrData(){
|
||||
const char* Caret::getCurrData(){
|
||||
return &m_data[m_pos];
|
||||
}
|
||||
|
||||
@ -173,7 +169,7 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::base::StrBuffer> Caret::getDataMemoryHandle() {
|
||||
std::shared_ptr<std::string> Caret::getDataMemoryHandle() {
|
||||
return m_dataMemoryHandle;
|
||||
}
|
||||
|
||||
@ -252,10 +248,10 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
}
|
||||
|
||||
bool Caret::skipCharsFromSet(const char* set){
|
||||
return skipCharsFromSet((p_char8)set, std::strlen(set));
|
||||
return skipCharsFromSet(set, std::strlen(set));
|
||||
}
|
||||
|
||||
bool Caret::skipCharsFromSet(p_char8 set, v_buff_size setSize){
|
||||
bool Caret::skipCharsFromSet(const char* set, v_buff_size setSize){
|
||||
|
||||
while(m_pos < m_size){
|
||||
if(!isAtCharFromSet(set, setSize)){
|
||||
@ -269,10 +265,10 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
}
|
||||
|
||||
v_buff_size Caret::findCharFromSet(const char* set){
|
||||
return findCharFromSet((p_char8) set, std::strlen(set));
|
||||
return findCharFromSet(set, std::strlen(set));
|
||||
}
|
||||
|
||||
v_buff_size Caret::findCharFromSet(p_char8 set, v_buff_size setSize){
|
||||
v_buff_size Caret::findCharFromSet(const char* set, v_buff_size setSize){
|
||||
|
||||
while(m_pos < m_size){
|
||||
|
||||
@ -399,10 +395,10 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
}
|
||||
|
||||
bool Caret::isAtText(const char* text, bool skipIfTrue){
|
||||
return isAtText((p_char8)text, std::strlen(text), skipIfTrue);
|
||||
return isAtText(text, std::strlen(text), skipIfTrue);
|
||||
}
|
||||
|
||||
bool Caret::isAtText(p_char8 text, v_buff_size textSize, bool skipIfTrue){
|
||||
bool Caret::isAtText(const char* text, v_buff_size textSize, bool skipIfTrue){
|
||||
|
||||
if(textSize <= m_size - m_pos){
|
||||
|
||||
@ -427,10 +423,10 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
}
|
||||
|
||||
bool Caret::isAtTextNCS(const char* text, bool skipIfTrue){
|
||||
return isAtTextNCS((p_char8)text, std::strlen(text), skipIfTrue);
|
||||
return isAtTextNCS(text, std::strlen(text), skipIfTrue);
|
||||
}
|
||||
|
||||
bool Caret::isAtTextNCS(p_char8 text, v_buff_size textSize, bool skipIfTrue){
|
||||
bool Caret::isAtTextNCS(const char* text, v_buff_size textSize, bool skipIfTrue){
|
||||
|
||||
if(textSize <= m_size - m_pos){
|
||||
|
||||
@ -496,19 +492,19 @@ v_int64 Caret::StateSaveGuard::getSavedErrorCode() {
|
||||
}
|
||||
|
||||
bool Caret::findText(const char* text) {
|
||||
return findText((p_char8) text, std::strlen(text));
|
||||
return findText(text, std::strlen(text));
|
||||
}
|
||||
|
||||
bool Caret::findText(p_char8 text, v_buff_size textSize) {
|
||||
bool Caret::findText(const char* text, v_buff_size textSize) {
|
||||
m_pos = (std::search(&m_data[m_pos], &m_data[m_size], text, text + textSize) - m_data);
|
||||
return m_pos != m_size;
|
||||
}
|
||||
|
||||
bool Caret::isAtCharFromSet(const char* set) const{
|
||||
return isAtCharFromSet((p_char8)set, std::strlen(set));
|
||||
return isAtCharFromSet(set, std::strlen(set));
|
||||
}
|
||||
|
||||
bool Caret::isAtCharFromSet(p_char8 set, v_buff_size setSize) const{
|
||||
bool Caret::isAtCharFromSet(const char* set, v_buff_size setSize) const{
|
||||
|
||||
v_char8 a = m_data[m_pos];
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
#ifndef oatpp_parser_Caret_hpp
|
||||
#define oatpp_parser_Caret_hpp
|
||||
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
#include "oatpp/core/Types.hpp"
|
||||
|
||||
namespace oatpp { namespace parser {
|
||||
@ -73,7 +72,7 @@ public:
|
||||
* Get pointer to a labeled data.
|
||||
* @return
|
||||
*/
|
||||
p_char8 getData();
|
||||
const char* getData();
|
||||
|
||||
/**
|
||||
* Get size of labeled data.
|
||||
@ -93,13 +92,6 @@ public:
|
||||
*/
|
||||
v_buff_size getEndPosition();
|
||||
|
||||
/**
|
||||
* Create &id:oatpp::String; from labeled data.
|
||||
* @param saveAsOwnData - `true` - allocate new memory block for string. `false` - string will point to the same data as label.
|
||||
* @return - &id:oatpp::String;.
|
||||
*/
|
||||
oatpp::String toString(bool saveAsOwnData);
|
||||
|
||||
/**
|
||||
* Same as`toString(true).`
|
||||
* @return - &id:oatpp::String;.
|
||||
@ -159,20 +151,20 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
p_char8 m_data;
|
||||
const char* m_data;
|
||||
v_buff_size m_size;
|
||||
v_buff_size m_pos;
|
||||
const char* m_errorMessage;
|
||||
v_int64 m_errorCode;
|
||||
std::shared_ptr<oatpp::base::StrBuffer> m_dataMemoryHandle;
|
||||
std::shared_ptr<std::string> m_dataMemoryHandle;
|
||||
public:
|
||||
Caret(const char* text);
|
||||
Caret(p_char8 parseData, v_buff_size dataSize);
|
||||
Caret(const char* parseData, v_buff_size dataSize);
|
||||
Caret(const oatpp::String& str);
|
||||
public:
|
||||
|
||||
static std::shared_ptr<Caret> createShared(const char* text);
|
||||
static std::shared_ptr<Caret> createShared(p_char8 parseData, v_buff_size dataSize);
|
||||
static std::shared_ptr<Caret> createShared(const char* parseData, v_buff_size dataSize);
|
||||
static std::shared_ptr<Caret> createShared(const oatpp::String& str);
|
||||
|
||||
virtual ~Caret();
|
||||
@ -181,13 +173,13 @@ public:
|
||||
* Get pointer to a data, passed to Caret constructor
|
||||
* @return
|
||||
*/
|
||||
p_char8 getData();
|
||||
const char* getData();
|
||||
|
||||
/**
|
||||
* Same as &getData()[position]
|
||||
* @return
|
||||
*/
|
||||
p_char8 getCurrData();
|
||||
const char* getCurrData();
|
||||
|
||||
/**
|
||||
* Get size of a data
|
||||
@ -199,7 +191,7 @@ public:
|
||||
* Get data memoryHandle.
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<oatpp::base::StrBuffer> getDataMemoryHandle();
|
||||
std::shared_ptr<std::string> getDataMemoryHandle();
|
||||
|
||||
/**
|
||||
* Set caret position relative to data
|
||||
@ -297,7 +289,7 @@ public:
|
||||
* @param setSize
|
||||
* @return true if other char found
|
||||
*/
|
||||
bool skipCharsFromSet(p_char8 set, v_buff_size setSize);
|
||||
bool skipCharsFromSet(const char* set, v_buff_size setSize);
|
||||
|
||||
/**
|
||||
* Find one of chars defined by set.
|
||||
@ -312,7 +304,7 @@ public:
|
||||
* @param setSize
|
||||
* @return char found or -1 if no char found
|
||||
*/
|
||||
v_buff_size findCharFromSet(p_char8 set, v_buff_size setSize);
|
||||
v_buff_size findCharFromSet(const char* set, v_buff_size setSize);
|
||||
|
||||
/**
|
||||
* Find "\r\n" chars
|
||||
@ -408,7 +400,7 @@ public:
|
||||
* @param skipIfTrue - increase position if true
|
||||
* @return
|
||||
*/
|
||||
bool isAtText(p_char8 text, v_buff_size textSize, bool skipIfTrue = false);
|
||||
bool isAtText(const char* text, v_buff_size textSize, bool skipIfTrue = false);
|
||||
|
||||
/**
|
||||
* Check if follows text (Not Case Sensitive)
|
||||
@ -425,7 +417,7 @@ public:
|
||||
* @param skipIfTrue - increase position if true
|
||||
* @return
|
||||
*/
|
||||
bool isAtTextNCS(p_char8 text, v_buff_size textSize, bool skipIfTrue = false);
|
||||
bool isAtTextNCS(const char* text, v_buff_size textSize, bool skipIfTrue = false);
|
||||
|
||||
/**
|
||||
* Parse enclosed string.
|
||||
@ -451,7 +443,7 @@ public:
|
||||
* @param textSize
|
||||
* @return true if found
|
||||
*/
|
||||
bool findText(p_char8 text, v_buff_size textSize);
|
||||
bool findText(const char* text, v_buff_size textSize);
|
||||
|
||||
/**
|
||||
* Check if caret is at char defined by set
|
||||
@ -468,7 +460,7 @@ public:
|
||||
* @param setSize
|
||||
* @return
|
||||
*/
|
||||
bool isAtCharFromSet(p_char8 set, v_buff_size setSize) const;
|
||||
bool isAtCharFromSet(const char* set, v_buff_size setSize) const;
|
||||
|
||||
/**
|
||||
* Check if caret is at char
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace oatpp { namespace parser {
|
||||
|
||||
ParsingError::ParsingError(const oatpp::String &message, v_int64 code, v_buff_size position)
|
||||
:std::runtime_error(message->std_str())
|
||||
:std::runtime_error(*message)
|
||||
, m_message(message)
|
||||
, m_code(code)
|
||||
, m_position(position)
|
||||
|
57
src/oatpp/core/provider/Invalidator.hpp
Normal file
57
src/oatpp/core/provider/Invalidator.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_provider_Invalidator_hpp
|
||||
#define oatpp_provider_Invalidator_hpp
|
||||
|
||||
#include "oatpp/core/base/Countable.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace oatpp { namespace provider {
|
||||
|
||||
/**
|
||||
* Abstract resource invalidator.
|
||||
* @tparam T - resource class.
|
||||
*/
|
||||
template<class T>
|
||||
class Invalidator : public oatpp::base::Countable {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default virtual destructor.
|
||||
*/
|
||||
virtual ~Invalidator() = default;
|
||||
|
||||
/**
|
||||
* Invalidate resource that was previously created by the correspondent provider. <br>
|
||||
* Use-case: if provider is pool based - you can signal that this resource should not be reused anymore.
|
||||
* @param resource
|
||||
*/
|
||||
virtual void invalidate(const std::shared_ptr<T> &resource) = 0;
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //oatpp_provider_Invalidator_hpp
|
@ -6,7 +6,8 @@
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
|
||||
* Matthias Haselmaier <mhaselmaier@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -55,12 +56,12 @@ private:
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
std::shared_ptr<TResource> __pool__getUnderlyingResource() {
|
||||
return _obj;
|
||||
provider::ResourceHandle<TResource> __pool__getUnderlyingResource() {
|
||||
return _handle;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<TResource> _obj;
|
||||
provider::ResourceHandle<TResource> _handle;
|
||||
private:
|
||||
std::shared_ptr<PoolInstance> m_pool;
|
||||
bool m_valid;
|
||||
@ -71,8 +72,8 @@ public:
|
||||
* @param resource - base resource.
|
||||
* @param pool - &l:AcquisitionProxy::PoolInstance;.
|
||||
*/
|
||||
AcquisitionProxy(const std::shared_ptr<TResource>& resource, const std::shared_ptr<PoolInstance>& pool)
|
||||
: _obj(resource)
|
||||
AcquisitionProxy(const provider::ResourceHandle<TResource>& resource, const std::shared_ptr<PoolInstance>& pool)
|
||||
: _handle(resource)
|
||||
, m_pool(pool)
|
||||
, m_valid(true)
|
||||
{}
|
||||
@ -81,7 +82,7 @@ public:
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~AcquisitionProxy() {
|
||||
m_pool->release(std::move(_obj), m_valid);
|
||||
m_pool->release(std::move(_handle), m_valid);
|
||||
}
|
||||
|
||||
};
|
||||
@ -92,10 +93,24 @@ class PoolTemplate : public oatpp::base::Countable, public async::CoroutineWaitL
|
||||
private:
|
||||
|
||||
struct PoolRecord {
|
||||
std::shared_ptr<TResource> resource;
|
||||
provider::ResourceHandle<TResource> resource;
|
||||
v_int64 timestamp;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class ResourceInvalidator : public provider::Invalidator<TResource> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<TResource>& resource) override {
|
||||
auto proxy = std::static_pointer_cast<AcquisitionProxyImpl>(resource);
|
||||
proxy->__pool__invalidate();
|
||||
const auto& handle = proxy->__pool__getUnderlyingResource();
|
||||
handle.invalidator->invalidate(handle.object);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void onNewItem(async::CoroutineWaitList& list) override {
|
||||
@ -115,7 +130,7 @@ private:
|
||||
|
||||
}
|
||||
|
||||
void release(std::shared_ptr<TResource>&& resource, bool canReuse) {
|
||||
void release(provider::ResourceHandle<TResource>&& resource, bool canReuse) {
|
||||
|
||||
{
|
||||
|
||||
@ -154,7 +169,7 @@ private:
|
||||
|
||||
auto elapsed = ticks - i->timestamp;
|
||||
if(elapsed > pool->m_maxResourceTTL) {
|
||||
pool->m_provider->invalidate(i->resource);
|
||||
i->resource.invalidator->invalidate(i->resource.object);
|
||||
i = pool->m_bench.erase(i);
|
||||
pool->m_counter --;
|
||||
} else {
|
||||
@ -174,7 +189,7 @@ private:
|
||||
std::lock_guard<std::mutex> guard(pool->m_lock);
|
||||
auto i = pool->m_bench.begin();
|
||||
while (i != pool->m_bench.end()) {
|
||||
pool->m_provider->invalidate(i->resource);
|
||||
i->resource.invalidator->invalidate(i->resource.object);
|
||||
i = pool->m_bench.erase(i);
|
||||
pool->m_counter --;
|
||||
}
|
||||
@ -188,97 +203,95 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ResourceInvalidator> m_invalidator;
|
||||
std::shared_ptr<Provider<TResource>> m_provider;
|
||||
v_int64 m_counter;
|
||||
v_int64 m_counter{0};
|
||||
v_int64 m_maxResources;
|
||||
v_int64 m_maxResourceTTL;
|
||||
std::atomic<bool> m_running;
|
||||
bool m_finished;
|
||||
std::atomic<bool> m_running{true};
|
||||
bool m_finished{false};
|
||||
private:
|
||||
std::list<PoolRecord> m_bench;
|
||||
async::CoroutineWaitList m_waitList;
|
||||
std::condition_variable m_condition;
|
||||
std::mutex m_lock;
|
||||
std::chrono::duration<v_int64, std::micro> m_timeout;
|
||||
protected:
|
||||
|
||||
PoolTemplate(const std::shared_ptr<Provider<TResource>>& provider, v_int64 maxResources, v_int64 maxResourceTTL)
|
||||
: m_provider(provider)
|
||||
, m_counter(0)
|
||||
PoolTemplate(const std::shared_ptr<Provider<TResource>>& provider, v_int64 maxResources, v_int64 maxResourceTTL, const std::chrono::duration<v_int64, std::micro>& timeout)
|
||||
: m_invalidator(std::make_shared<ResourceInvalidator>())
|
||||
, m_provider(provider)
|
||||
, m_maxResources(maxResources)
|
||||
, m_maxResourceTTL(maxResourceTTL)
|
||||
, m_running(true)
|
||||
, m_finished(false)
|
||||
, m_timeout(timeout)
|
||||
{}
|
||||
|
||||
void startCleanupTask(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
static void startCleanupTask(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
std::thread poolCleanupTask(cleanupTask, _this);
|
||||
poolCleanupTask.detach();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static std::shared_ptr<PoolTemplate> createShared(const std::shared_ptr<Provider<TResource>>& provider,
|
||||
v_int64 maxResources,
|
||||
const std::chrono::duration<v_int64, std::micro>& maxResourceTTL)
|
||||
{
|
||||
/* "new" is called directly to keep constructor private */
|
||||
auto ptr = std::shared_ptr<PoolTemplate>(new PoolTemplate(provider, maxResources, maxResourceTTL.count()));
|
||||
ptr->startCleanupTask();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
virtual ~PoolTemplate() {
|
||||
stop();
|
||||
}
|
||||
|
||||
std::shared_ptr<TResource> get(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
static provider::ResourceHandle<TResource> get(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
auto readyPredicate = [&_this]() { return !_this->m_running || !_this->m_bench.empty() || _this->m_counter < _this->m_maxResources; };
|
||||
|
||||
std::unique_lock<std::mutex> guard{_this->m_lock};
|
||||
if (_this->m_timeout == std::chrono::microseconds::zero())
|
||||
{
|
||||
|
||||
std::unique_lock<std::mutex> guard(m_lock);
|
||||
|
||||
while (m_running && m_bench.size() == 0 && m_counter >= m_maxResources ) {
|
||||
m_condition.wait(guard);
|
||||
while (!readyPredicate()) {
|
||||
_this->m_condition.wait(guard);
|
||||
}
|
||||
} else if (!_this->m_condition.wait_for(guard, _this->m_timeout, std::move(readyPredicate))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!m_running) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_bench.size() > 0) {
|
||||
auto record = m_bench.front();
|
||||
m_bench.pop_front();
|
||||
return std::make_shared<AcquisitionProxyImpl>(record.resource, _this);
|
||||
} else {
|
||||
++ m_counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
return std::make_shared<AcquisitionProxyImpl>(m_provider->get(), _this);
|
||||
} catch (...) {
|
||||
std::lock_guard<std::mutex> guard(m_lock);
|
||||
-- m_counter;
|
||||
if(!_this->m_running) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_this->m_bench.size() > 0) {
|
||||
auto record = _this->m_bench.front();
|
||||
_this->m_bench.pop_front();
|
||||
return provider::ResourceHandle<TResource>(
|
||||
std::make_shared<AcquisitionProxyImpl>(record.resource, _this),
|
||||
_this->m_invalidator
|
||||
);
|
||||
} else {
|
||||
++ _this->m_counter;
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
|
||||
try {
|
||||
return provider::ResourceHandle<TResource>(
|
||||
std::make_shared<AcquisitionProxyImpl>(_this->m_provider->get(), _this),
|
||||
_this->m_invalidator
|
||||
);
|
||||
} catch (...) {
|
||||
guard.lock();
|
||||
--_this->m_counter;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
async::CoroutineStarterForResult<const std::shared_ptr<TResource>&> getAsync(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
static async::CoroutineStarterForResult<const provider::ResourceHandle<TResource>&> getAsync(const std::shared_ptr<PoolTemplate>& _this) {
|
||||
|
||||
class GetCoroutine : public oatpp::async::CoroutineWithResult<GetCoroutine, const std::shared_ptr<TResource>&> {
|
||||
class GetCoroutine : public oatpp::async::CoroutineWithResult<GetCoroutine, const provider::ResourceHandle<TResource>&> {
|
||||
private:
|
||||
std::shared_ptr<PoolTemplate> m_pool;
|
||||
std::shared_ptr<Provider<TResource>> m_provider;
|
||||
std::chrono::steady_clock::time_point m_startTime{std::chrono::steady_clock::now()};
|
||||
public:
|
||||
|
||||
GetCoroutine(const std::shared_ptr<PoolTemplate>& pool, const std::shared_ptr<Provider<TResource>>& provider)
|
||||
GetCoroutine(const std::shared_ptr<PoolTemplate>& pool)
|
||||
: m_pool(pool)
|
||||
, m_provider(provider)
|
||||
{}
|
||||
|
||||
bool timedout() const noexcept {
|
||||
return m_pool->m_timeout != std::chrono::microseconds::zero() && m_pool->m_timeout < (std::chrono::steady_clock::now() - m_startTime);
|
||||
}
|
||||
|
||||
async::Action act() override {
|
||||
|
||||
if (timedout()) return this->_return(nullptr);
|
||||
|
||||
{
|
||||
/* Careful!!! Using non-async lock */
|
||||
@ -286,7 +299,9 @@ public:
|
||||
|
||||
if (m_pool->m_running && m_pool->m_bench.size() == 0 && m_pool->m_counter >= m_pool->m_maxResources) {
|
||||
guard.unlock();
|
||||
return async::Action::createWaitListAction(&m_pool->m_waitList);
|
||||
return m_pool->m_timeout == std::chrono::microseconds::zero()
|
||||
? async::Action::createWaitListAction(&m_pool->m_waitList)
|
||||
: async::Action::createWaitListActionWithTimeout(&m_pool->m_waitList, m_startTime + m_pool->m_timeout);
|
||||
}
|
||||
|
||||
if(!m_pool->m_running) {
|
||||
@ -298,19 +313,25 @@ public:
|
||||
auto record = m_pool->m_bench.front();
|
||||
m_pool->m_bench.pop_front();
|
||||
guard.unlock();
|
||||
return this->_return(std::make_shared<AcquisitionProxyImpl>(record.resource, m_pool));
|
||||
return this->_return(provider::ResourceHandle<TResource>(
|
||||
std::make_shared<AcquisitionProxyImpl>(record.resource, m_pool),
|
||||
m_pool->m_invalidator
|
||||
));
|
||||
} else {
|
||||
++ m_pool->m_counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return m_provider->getAsync().callbackTo(&GetCoroutine::onGet);
|
||||
return m_pool->m_provider->getAsync().callbackTo(&GetCoroutine::onGet);
|
||||
|
||||
}
|
||||
|
||||
async::Action onGet(const std::shared_ptr<TResource>& resource) {
|
||||
return this->_return(std::make_shared<AcquisitionProxyImpl>(resource, m_pool));
|
||||
async::Action onGet(const provider::ResourceHandle<TResource>& resource) {
|
||||
return this->_return(provider::ResourceHandle<TResource>(
|
||||
std::make_shared<AcquisitionProxyImpl>(resource, m_pool),
|
||||
m_pool->m_invalidator
|
||||
));
|
||||
}
|
||||
|
||||
async::Action handleError(oatpp::async::Error* error) override {
|
||||
@ -324,14 +345,24 @@ public:
|
||||
|
||||
};
|
||||
|
||||
return GetCoroutine::startForResult(_this, m_provider);
|
||||
return GetCoroutine::startForResult(_this);
|
||||
|
||||
}
|
||||
|
||||
void invalidate(const std::shared_ptr<TResource>& resource) {
|
||||
auto proxy = std::static_pointer_cast<AcquisitionProxyImpl>(resource);
|
||||
proxy->__pool__invalidate();
|
||||
m_provider->invalidate(proxy->__pool__getUnderlyingResource());
|
||||
public:
|
||||
|
||||
static std::shared_ptr<PoolTemplate> createShared(const std::shared_ptr<Provider<TResource>>& provider,
|
||||
v_int64 maxResources,
|
||||
const std::chrono::duration<v_int64, std::micro>& maxResourceTTL)
|
||||
{
|
||||
/* "new" is called directly to keep constructor private */
|
||||
auto ptr = std::shared_ptr<PoolTemplate>(new PoolTemplate(provider, maxResources, maxResourceTTL.count()));
|
||||
startCleanupTask(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
virtual ~PoolTemplate() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
@ -385,14 +416,19 @@ private:
|
||||
typedef PoolTemplate<TResource, AcquisitionProxyImpl> TPool;
|
||||
protected:
|
||||
|
||||
/**
|
||||
/*
|
||||
* Protected Constructor.
|
||||
* @param provider
|
||||
* @param maxResources
|
||||
* @param maxResourceTTL
|
||||
* @param timeout
|
||||
*/
|
||||
Pool(const std::shared_ptr<TProvider>& provider, v_int64 maxResources, v_int64 maxResourceTTL)
|
||||
: PoolTemplate<TResource, AcquisitionProxyImpl>(provider, maxResources, maxResourceTTL)
|
||||
Pool(const std::shared_ptr<TProvider>& provider,
|
||||
v_int64 maxResources,
|
||||
v_int64 maxResourceTTL,
|
||||
const std::chrono::duration<v_int64, std::micro>& timeout = std::chrono::microseconds::zero()
|
||||
)
|
||||
: PoolTemplate<TResource, AcquisitionProxyImpl>(provider, maxResources, maxResourceTTL, timeout)
|
||||
{
|
||||
TProvider::m_properties = provider->getProperties();
|
||||
}
|
||||
@ -404,14 +440,16 @@ public:
|
||||
* @param provider - resource provider.
|
||||
* @param maxResources - max resource count in the pool.
|
||||
* @param maxResourceTTL - max time-to-live for unused resource in the pool.
|
||||
* @param timeout - optional timeout on &l:Pool::get (); and &l:Pool::getAsync (); operations.
|
||||
* @return - `std::shared_ptr` of `Pool`.
|
||||
*/
|
||||
static std::shared_ptr<Pool> createShared(const std::shared_ptr<TProvider>& provider,
|
||||
v_int64 maxResources,
|
||||
const std::chrono::duration<v_int64, std::micro>& maxResourceTTL)
|
||||
const std::chrono::duration<v_int64, std::micro>& maxResourceTTL,
|
||||
const std::chrono::duration<v_int64, std::micro>& timeout = std::chrono::microseconds::zero())
|
||||
{
|
||||
/* "new" is called directly to keep constructor private */
|
||||
auto ptr = std::shared_ptr<Pool>(new Pool(provider, maxResources, maxResourceTTL.count()));
|
||||
auto ptr = std::shared_ptr<Pool>(new Pool(provider, maxResources, maxResourceTTL.count(), timeout));
|
||||
ptr->startCleanupTask(ptr);
|
||||
return ptr;
|
||||
}
|
||||
@ -420,7 +458,7 @@ public:
|
||||
* Get resource.
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<TResource> get() override {
|
||||
provider::ResourceHandle<TResource> get() override {
|
||||
return TPool::get(this->shared_from_this());
|
||||
}
|
||||
|
||||
@ -428,18 +466,10 @@ public:
|
||||
* Get resource asynchronously.
|
||||
* @return
|
||||
*/
|
||||
async::CoroutineStarterForResult<const std::shared_ptr<TResource>&> getAsync() override {
|
||||
async::CoroutineStarterForResult<const provider::ResourceHandle<TResource>&> getAsync() override {
|
||||
return TPool::getAsync(this->shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate resource.
|
||||
* @param resource
|
||||
*/
|
||||
void invalidate(const std::shared_ptr<TResource>& resource) override {
|
||||
TPool::invalidate(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop pool. <br>
|
||||
* *Note: call to stop() may block.*
|
||||
|
@ -25,17 +25,128 @@
|
||||
#ifndef oatpp_provider_Provider_hpp
|
||||
#define oatpp_provider_Provider_hpp
|
||||
|
||||
#include "Invalidator.hpp"
|
||||
|
||||
#include "oatpp/core/async/Coroutine.hpp"
|
||||
#include "oatpp/core/data/share/MemoryLabel.hpp"
|
||||
|
||||
namespace oatpp { namespace provider {
|
||||
|
||||
/**
|
||||
* Resource handle template.
|
||||
* @tparam T
|
||||
*/
|
||||
template<class T, class PTR>
|
||||
struct ResourceHandleTemplate {
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
ResourceHandleTemplate() = default;
|
||||
|
||||
/**
|
||||
* Nullptr constructor.
|
||||
*/
|
||||
ResourceHandleTemplate(std::nullptr_t) {}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param resourceObject
|
||||
* @param resourceInvalidator
|
||||
*/
|
||||
ResourceHandleTemplate(const PTR& resourceObject,
|
||||
const std::shared_ptr<Invalidator<T>> &resourceInvalidator)
|
||||
: object(resourceObject), invalidator(resourceInvalidator)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Pointer to the resource.
|
||||
*/
|
||||
PTR object;
|
||||
|
||||
/**
|
||||
* Invalidator that can be used to invalidate the resource.
|
||||
*/
|
||||
std::shared_ptr<Invalidator<T>> invalidator;
|
||||
|
||||
inline bool operator == (std::nullptr_t) const {
|
||||
return object.get() == nullptr;
|
||||
}
|
||||
|
||||
inline bool operator != (std::nullptr_t) const {
|
||||
return object.get() != nullptr;
|
||||
}
|
||||
|
||||
explicit inline operator bool() const {
|
||||
return object.operator bool();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Resource handle.
|
||||
* @tparam T
|
||||
*/
|
||||
template<class T>
|
||||
struct ResourceHandle : public ResourceHandleTemplate<T, std::shared_ptr<T>> {
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
ResourceHandle() = default;
|
||||
|
||||
/**
|
||||
* Nullptr constructor.
|
||||
*/
|
||||
ResourceHandle(std::nullptr_t) {}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param resourceObject
|
||||
* @param resourceInvalidator
|
||||
*/
|
||||
ResourceHandle(const std::shared_ptr<T>& resourceObject,
|
||||
const std::shared_ptr<Invalidator<T>>& resourceInvalidator)
|
||||
: ResourceHandleTemplate<T, std::shared_ptr<T>>(resourceObject, resourceInvalidator)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Weak Resource handle.
|
||||
* @tparam T
|
||||
*/
|
||||
template<class T>
|
||||
struct WeakResourceHandle : public ResourceHandleTemplate<T, std::weak_ptr<T>> {
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
WeakResourceHandle() = default;
|
||||
|
||||
/**
|
||||
* Nullptr constructor.
|
||||
*/
|
||||
WeakResourceHandle(std::nullptr_t) {}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param resourceObject
|
||||
* @param resourceInvalidator
|
||||
*/
|
||||
WeakResourceHandle(const std::weak_ptr<T>& resourceObject,
|
||||
const std::shared_ptr<Invalidator<T>>& resourceInvalidator)
|
||||
: ResourceHandleTemplate<T, std::weak_ptr<T>>(resourceObject, resourceInvalidator)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract resource provider.
|
||||
* @tparam T - resource class.
|
||||
*/
|
||||
template <class T>
|
||||
class Provider {
|
||||
class Provider : public oatpp::base::Countable {
|
||||
protected:
|
||||
|
||||
void setProperty(const oatpp::String& key, const oatpp::String& value) {
|
||||
@ -68,7 +179,7 @@ public:
|
||||
* Some optional properties that user might want to know. <br>
|
||||
* Note: All properties are optional and user should not rely on this.
|
||||
*/
|
||||
const std::unordered_map<oatpp::data::share::StringKeyLabelCI, oatpp::data::share::StringKeyLabel>& getProperties() const {
|
||||
const std::unordered_map<data::share::StringKeyLabelCI, data::share::StringKeyLabel>& getProperties() const {
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
@ -87,20 +198,13 @@ public:
|
||||
* Get resource.
|
||||
* @return - resource.
|
||||
*/
|
||||
virtual std::shared_ptr<T> get() = 0;
|
||||
virtual ResourceHandle<T> get() = 0;
|
||||
|
||||
/**
|
||||
* Get resource in Async manner.
|
||||
* @return - &id:oatpp::async::CoroutineStarterForResult; of `T`.
|
||||
*/
|
||||
virtual async::CoroutineStarterForResult<const std::shared_ptr<T>&> getAsync() = 0;
|
||||
|
||||
/**
|
||||
* Invalidate resource that was previously created by this provider. <br>
|
||||
* Use-case: if provider is pool based - you can signal that this resource should not be reused anymore.
|
||||
* @param resource
|
||||
*/
|
||||
virtual void invalidate(const std::shared_ptr<T>& resource) = 0;
|
||||
virtual async::CoroutineStarterForResult<const ResourceHandle<T>&> getAsync() = 0;
|
||||
|
||||
/**
|
||||
* Stop provider and free associated resources.
|
||||
|
@ -35,8 +35,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_int32 strToInt32(const oatpp::String& str, bool& success){
|
||||
char* end;
|
||||
v_int32 result = (v_int32) std::strtol((const char*)str->getData(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_int32 result = (v_int32) std::strtol(str->data(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -47,8 +47,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_uint32 strToUInt32(const oatpp::String& str, bool& success){
|
||||
char* end;
|
||||
v_uint32 result = (v_uint32) std::strtoul((const char*)str->getData(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_uint32 result = (v_uint32) std::strtoul(str->data(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -59,8 +59,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_int64 strToInt64(const oatpp::String& str, bool& success){
|
||||
char* end;
|
||||
v_int64 result = std::strtoll((const char*)str->getData(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_int64 result = std::strtoll(str->data(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -71,8 +71,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_uint64 strToUInt64(const oatpp::String& str, bool& success){
|
||||
char* end;
|
||||
v_uint64 result = std::strtoull((const char*)str->getData(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_uint64 result = std::strtoull(str->data(), &end, 10);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
v_char8 buff [16]; // Max 10 digits with 1 sign. 16 is plenty enough.
|
||||
auto size = int32ToCharSequence(value, &buff[0], 16);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
v_char8 buff [16]; // Max 10 digits. 16 is plenty enough.
|
||||
auto size = uint32ToCharSequence(value, &buff[0], 16);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -114,7 +114,7 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
v_char8 buff [32]; // Max 20 digits unsigned, 19 digits +1 sign signed.
|
||||
auto size = int64ToCharSequence(value, &buff[0], 32);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -123,7 +123,7 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
v_char8 buff [32]; // Max 20 digits.
|
||||
auto size = uint64ToCharSequence(value, &buff[0], 32);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -171,8 +171,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_float32 strToFloat32(const oatpp::String& str, bool& success) {
|
||||
char* end;
|
||||
v_float32 result = std::strtof((const char*)str->getData(), &end);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_float32 result = std::strtof(str->data(), &end);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -183,8 +183,8 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
|
||||
v_float64 strToFloat64(const oatpp::String& str, bool& success) {
|
||||
char* end;
|
||||
v_float64 result = std::strtod((const char*)str->getData(), &end);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->getData()) == str->getSize());
|
||||
v_float64 result = std::strtod(str->data(), &end);
|
||||
success = (((v_buff_size)end - (v_buff_size)str->data()) == str->size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ v_buff_size float64ToCharSequence(v_float64 value, p_char8 data, v_buff_size n,
|
||||
v_char8 buff [100];
|
||||
auto size = float32ToCharSequence(value, &buff[0], 100, format);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -209,24 +209,24 @@ v_buff_size float64ToCharSequence(v_float64 value, p_char8 data, v_buff_size n,
|
||||
v_char8 buff [100];
|
||||
auto size = float64ToCharSequence(value, &buff[0], 100, format);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
oatpp::String boolToStr(bool value) {
|
||||
if(value){
|
||||
return oatpp::String("true", 4, false);
|
||||
return oatpp::String("true", 4);
|
||||
} else {
|
||||
return oatpp::String("false", 5, false);
|
||||
return oatpp::String("false", 5);
|
||||
}
|
||||
}
|
||||
|
||||
bool strToBool(const oatpp::String& str, bool& success) {
|
||||
if(str->equals((p_char8)"true", 4)){
|
||||
if(str == "true"){
|
||||
success = true;
|
||||
return true;
|
||||
} else if(str->equals((p_char8)"false", 5)){
|
||||
} else if(str == "false"){
|
||||
success = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ namespace oatpp { namespace utils { namespace conversion {
|
||||
v_char8 buff [100];
|
||||
auto size = primitiveToCharSequence(value, &buff[0], 100, pattern);
|
||||
if(size > 0){
|
||||
return oatpp::String((const char*)&buff[0], size, true);
|
||||
return oatpp::String((const char*)&buff[0], size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
99
src/oatpp/core/utils/String.cpp
Normal file
99
src/oatpp/core/utils/String.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "String.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace oatpp { namespace utils {
|
||||
|
||||
v_buff_size String::compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2) {
|
||||
|
||||
if(data1 == data2) return 0;
|
||||
if(data1 == nullptr) return -1;
|
||||
if(data2 == nullptr) return 1;
|
||||
|
||||
if(size1 < size2) {
|
||||
auto res = std::memcmp(data1, data2, size1);
|
||||
if(res == 0) return -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
if(size1 > size2) {
|
||||
auto res = std::memcmp(data1, data2, size2);
|
||||
if(res == 0) return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return std::memcmp(data1, data2, size1);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
if(data2 == nullptr) return 1;
|
||||
|
||||
auto d1 = (p_char8) data1;
|
||||
auto d2 = (p_char8) data2;
|
||||
|
||||
v_buff_size size = size1;
|
||||
if(size2 < size1) size = size2;
|
||||
|
||||
for(v_buff_size i = 0; i < size; i ++) {
|
||||
|
||||
v_char8 a = d1[i];
|
||||
v_char8 b = d2[i];
|
||||
|
||||
if(a >= 'A' && a <= 'Z') a |= 32;
|
||||
if(b >= 'A' && b <= 'Z') b |= 32;
|
||||
|
||||
if(a != b) {
|
||||
return (int) a - (int) b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(size1 < size2) return -1;
|
||||
if(size1 > size2) return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
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::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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
82
src/oatpp/core/utils/String.hpp
Normal file
82
src/oatpp/core/utils/String.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_utils_String_hpp
|
||||
#define oatpp_utils_String_hpp
|
||||
|
||||
#include "oatpp/core/base/Environment.hpp"
|
||||
|
||||
namespace oatpp { namespace utils {
|
||||
|
||||
/**
|
||||
* Utility class for Strings
|
||||
*/
|
||||
class String {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Compare data1, data2 using `std::memcmp`.
|
||||
* *It's safe to pass nullptr for data1/data2*
|
||||
* @param data1 - pointer to data1.
|
||||
* @param size1 - size of data1.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of data2.
|
||||
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
|
||||
* 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 compare(const void* data1, v_buff_size size1, const void* data2, v_buff_size size2);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param data2 - pointer to data2.
|
||||
* @param size2 - size of data2.
|
||||
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
|
||||
* 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_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 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 upperCase_ASCII(void* data, v_buff_size size);
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // oatpp_utils_String_hpp
|
@ -110,7 +110,7 @@ oatpp::String Base64::encode(const void* data, v_buff_size size, const char* alp
|
||||
auto result = oatpp::String(resultSize);
|
||||
|
||||
p_char8 bdata = (p_char8) data;
|
||||
p_char8 resultData = result->getData();
|
||||
p_char8 resultData = (p_char8) result->data();
|
||||
|
||||
v_buff_size pos = 0;
|
||||
while (pos + 2 < size) {
|
||||
@ -147,7 +147,7 @@ oatpp::String Base64::encode(const void* data, v_buff_size size, const char* alp
|
||||
}
|
||||
|
||||
oatpp::String Base64::encode(const oatpp::String& data, const char* alphabet) {
|
||||
return encode(data->getData(), data->getSize(), alphabet);
|
||||
return encode(data->data(), data->size(), alphabet);
|
||||
}
|
||||
|
||||
oatpp::String Base64::decode(const char* data, v_buff_size size, const char* auxiliaryChars) {
|
||||
@ -159,7 +159,7 @@ oatpp::String Base64::decode(const char* data, v_buff_size size, const char* aux
|
||||
}
|
||||
|
||||
auto result = oatpp::String(resultSize);
|
||||
p_char8 resultData = result->getData();
|
||||
p_char8 resultData = (p_char8) result->data();
|
||||
v_buff_size pos = 0;
|
||||
while (pos + 3 < base64StrLength) {
|
||||
v_char8 b0 = getAlphabetCharIndex(data[pos], auxiliaryChars);
|
||||
@ -193,7 +193,7 @@ oatpp::String Base64::decode(const char* data, v_buff_size size, const char* aux
|
||||
}
|
||||
|
||||
oatpp::String Base64::decode(const oatpp::String& data, const char* auxiliaryChars) {
|
||||
return decode((const char*)data->getData(), data->getSize(), auxiliaryChars);
|
||||
return decode((const char*)data->data(), data->size(), auxiliaryChars);
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -48,7 +48,7 @@ void Hex::writeUInt32(v_uint32 value, p_char8 buffer){
|
||||
writeUInt16(v_uint16(value), buffer + 4);
|
||||
}
|
||||
|
||||
v_int32 Hex::readUInt16(p_char8 buffer, v_uint16& value) {
|
||||
v_int32 Hex::readUInt16(const char* buffer, v_uint16& value) {
|
||||
value = 0;
|
||||
for(v_int32 i = 0; i < 4; i++){
|
||||
v_char8 a = buffer[i];
|
||||
@ -65,7 +65,7 @@ v_int32 Hex::readUInt16(p_char8 buffer, v_uint16& value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v_int32 Hex::readUInt32(p_char8 buffer, v_uint32& value) {
|
||||
v_int32 Hex::readUInt32(const char* buffer, v_uint32& value) {
|
||||
value = 0;
|
||||
for(v_int32 i = 0; i < 8; i++){
|
||||
v_char8 a = buffer[i];
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
* @param value - out parameter. Resultant value.
|
||||
* @return - 0 on success. Negative value on failure.
|
||||
*/
|
||||
static v_int32 readUInt16(p_char8 buffer, v_uint16& value);
|
||||
static v_int32 readUInt16(const char* buffer, v_uint16& value);
|
||||
|
||||
/**
|
||||
* Parse 8-char hex string to int32.
|
||||
@ -90,7 +90,7 @@ public:
|
||||
* @param value - out parameter. Resultant value.
|
||||
* @return - 0 on success. Negative value on failure.
|
||||
*/
|
||||
static v_int32 readUInt32(p_char8 buffer, v_uint32& value);
|
||||
static v_int32 readUInt32(const char* buffer, v_uint32& value);
|
||||
|
||||
/**
|
||||
* Write binary data as HEX string.
|
||||
|
@ -74,7 +74,7 @@ v_buff_size Unicode::getUtf8CharSequenceLengthForCode(v_uint32 code){
|
||||
}
|
||||
}
|
||||
|
||||
v_int32 Unicode::encodeUtf8Char(p_char8 sequence, v_buff_size& length){
|
||||
v_int32 Unicode::encodeUtf8Char(const char* sequence, v_buff_size& length){
|
||||
v_char8 byte = sequence[0];
|
||||
if(byte > 127){
|
||||
v_int32 code;
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
* @param length - out parameter. Length in bytes of UTF-8 character.
|
||||
* @return - code of UTF-8 character.
|
||||
*/
|
||||
static v_int32 encodeUtf8Char(p_char8 sequence, v_buff_size& length);
|
||||
static v_int32 encodeUtf8Char(const char* sequence, v_buff_size& length);
|
||||
|
||||
/**
|
||||
* Write UTF-8 character to buffer.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef oatpp_network_ConnectionHandler_hpp
|
||||
#define oatpp_network_ConnectionHandler_hpp
|
||||
|
||||
#include "oatpp/core/provider/Provider.hpp"
|
||||
#include "oatpp/core/data/stream/Stream.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
@ -53,10 +54,11 @@ public:
|
||||
|
||||
/**
|
||||
* Handle provided connection.
|
||||
* @param connection - see &id:oatpp::data::stream::IOStream;.
|
||||
* @param connectionData - see &id:oatpp::data::stream::IOStream;.
|
||||
* @param params - accompanying parameters.
|
||||
*/
|
||||
virtual void handleConnection(const std::shared_ptr<IOStream>& connection, const std::shared_ptr<const ParameterMap>& params) = 0;
|
||||
virtual void handleConnection(const provider::ResourceHandle<IOStream>& connectionData,
|
||||
const std::shared_ptr<const ParameterMap>& params) = 0;
|
||||
|
||||
/**
|
||||
* Stop all threads here
|
||||
|
@ -24,44 +24,41 @@
|
||||
|
||||
#include "ConnectionPool.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
namespace oatpp { namespace network {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionAcquisitionProxy
|
||||
|
||||
v_io_size ConnectionAcquisitionProxy::write(const void *buff, v_buff_size count, async::Action& action) {
|
||||
return _obj->write(buff, count, action);
|
||||
return _handle.object->write(buff, count, action);
|
||||
}
|
||||
|
||||
v_io_size ConnectionAcquisitionProxy::read(void *buff, v_buff_size count, async::Action& action) {
|
||||
return _obj->read(buff, count, action);
|
||||
return _handle.object->read(buff, count, action);
|
||||
}
|
||||
|
||||
void ConnectionAcquisitionProxy::setOutputStreamIOMode(oatpp::data::stream::IOMode ioMode) {
|
||||
return _obj->setOutputStreamIOMode(ioMode);
|
||||
return _handle.object->setOutputStreamIOMode(ioMode);
|
||||
}
|
||||
|
||||
oatpp::data::stream::IOMode ConnectionAcquisitionProxy::getOutputStreamIOMode() {
|
||||
return _obj->getOutputStreamIOMode();
|
||||
return _handle.object->getOutputStreamIOMode();
|
||||
}
|
||||
|
||||
void ConnectionAcquisitionProxy::setInputStreamIOMode(oatpp::data::stream::IOMode ioMode) {
|
||||
return _obj->setInputStreamIOMode(ioMode);
|
||||
return _handle.object->setInputStreamIOMode(ioMode);
|
||||
}
|
||||
|
||||
oatpp::data::stream::IOMode ConnectionAcquisitionProxy::getInputStreamIOMode() {
|
||||
return _obj->getInputStreamIOMode();
|
||||
return _handle.object->getInputStreamIOMode();
|
||||
}
|
||||
|
||||
oatpp::data::stream::Context& ConnectionAcquisitionProxy::getOutputStreamContext() {
|
||||
return _obj->getOutputStreamContext();
|
||||
return _handle.object->getOutputStreamContext();
|
||||
}
|
||||
|
||||
oatpp::data::stream::Context& ConnectionAcquisitionProxy::getInputStreamContext() {
|
||||
return _obj->getInputStreamContext();
|
||||
return _handle.object->getInputStreamContext();
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -36,7 +36,7 @@ namespace oatpp { namespace network {
|
||||
*/
|
||||
struct ConnectionAcquisitionProxy : public provider::AcquisitionProxy<data::stream::IOStream, ConnectionAcquisitionProxy> {
|
||||
|
||||
ConnectionAcquisitionProxy(const std::shared_ptr<data::stream::IOStream>& resource,
|
||||
ConnectionAcquisitionProxy(const provider::ResourceHandle<data::stream::IOStream>& resource,
|
||||
const std::shared_ptr<PoolInstance>& pool)
|
||||
: provider::AcquisitionProxy<data::stream::IOStream, ConnectionAcquisitionProxy>(resource, pool)
|
||||
{}
|
||||
|
@ -22,8 +22,8 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_netword_ConnectionsProvider_hpp
|
||||
#define oatpp_netword_ConnectionsProvider_hpp
|
||||
#ifndef oatpp_network_ConnectionProvider_hpp
|
||||
#define oatpp_network_ConnectionProvider_hpp
|
||||
|
||||
#include "oatpp/core/data/share/MemoryLabel.hpp"
|
||||
#include "oatpp/core/data/stream/Stream.hpp"
|
||||
@ -57,15 +57,15 @@ public:
|
||||
/**
|
||||
* No properties here. It is just a logical division
|
||||
*/
|
||||
class ServerConnectionProvider : public ConnectionProvider {
|
||||
class ServerConnectionProvider : virtual public ConnectionProvider {
|
||||
};
|
||||
|
||||
/**
|
||||
* No properties here. It is just a logical division
|
||||
*/
|
||||
class ClientConnectionProvider : public ConnectionProvider {
|
||||
class ClientConnectionProvider : virtual public ConnectionProvider {
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* oatpp_netword_ConnectionsProvider_hpp */
|
||||
#endif /* oatpp_network_ConnectionProvider_hpp */
|
||||
|
73
src/oatpp/network/ConnectionProviderSwitch.cpp
Normal file
73
src/oatpp/network/ConnectionProviderSwitch.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ConnectionProviderSwitch.hpp"
|
||||
|
||||
namespace oatpp { namespace network {
|
||||
|
||||
ConnectionProviderSwitch::ConnectionProviderSwitch(const std::shared_ptr<ConnectionProvider>& provider)
|
||||
: m_provider(provider)
|
||||
{}
|
||||
|
||||
void ConnectionProviderSwitch::resetProvider(const std::shared_ptr<ConnectionProvider>& provider) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_provider = provider;
|
||||
m_properties = provider->getProperties();
|
||||
}
|
||||
|
||||
std::shared_ptr<ConnectionProvider> ConnectionProviderSwitch::getCurrentProvider() {
|
||||
|
||||
std::shared_ptr<ConnectionProvider> provider;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
provider = m_provider;
|
||||
}
|
||||
|
||||
if(!provider) {
|
||||
const char* const TAG = "[oatpp::network::ConnectionProviderSwitch::getCurrentProvider()]";
|
||||
const char* const msg = "Error. Can't provide connection. There is no provider set.";
|
||||
OATPP_LOGE(TAG, msg)
|
||||
throw std::runtime_error(std::string(TAG) + ": " + msg);
|
||||
}
|
||||
|
||||
return provider;
|
||||
|
||||
}
|
||||
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProviderSwitch::get() {
|
||||
return getCurrentProvider()->get();
|
||||
}
|
||||
|
||||
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> ConnectionProviderSwitch::getAsync() {
|
||||
return getCurrentProvider()->getAsync();
|
||||
}
|
||||
|
||||
|
||||
void ConnectionProviderSwitch::stop() {
|
||||
return getCurrentProvider()->stop();
|
||||
}
|
||||
|
||||
}}
|
83
src/oatpp/network/ConnectionProviderSwitch.hpp
Normal file
83
src/oatpp/network/ConnectionProviderSwitch.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_ConnectionProviderSwitch_hpp
|
||||
#define oatpp_network_ConnectionProviderSwitch_hpp
|
||||
|
||||
#include "ConnectionProvider.hpp"
|
||||
#include <mutex>
|
||||
|
||||
namespace oatpp { namespace network {
|
||||
|
||||
/**
|
||||
* ConnectionProviderSwitch can be used to hot-change connection providers.
|
||||
* Ex.: to hot-reload server certificate.
|
||||
*/
|
||||
class ConnectionProviderSwitch : public ServerConnectionProvider, public ClientConnectionProvider {
|
||||
private:
|
||||
std::shared_ptr<ConnectionProvider> getCurrentProvider();
|
||||
private:
|
||||
std::shared_ptr<ConnectionProvider> m_provider;
|
||||
std::mutex m_mutex;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
ConnectionProviderSwitch() = default;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param provider
|
||||
*/
|
||||
ConnectionProviderSwitch(const std::shared_ptr<ConnectionProvider>& provider);
|
||||
|
||||
/**
|
||||
* Reset current provider.
|
||||
* @param provider
|
||||
*/
|
||||
void resetProvider(const std::shared_ptr<ConnectionProvider>& provider);
|
||||
|
||||
/**
|
||||
* Get new connection.
|
||||
* @return &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
/**
|
||||
* Get new connection.
|
||||
* @return &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
/**
|
||||
* Stop current provider.
|
||||
*/
|
||||
void stop() override;
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //oatpp_network_ConnectionProviderSwitch_hpp
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
namespace oatpp { namespace network {
|
||||
|
||||
@ -36,7 +35,7 @@ const v_int32 Server::STATUS_RUNNING = 2;
|
||||
const v_int32 Server::STATUS_STOPPING = 3;
|
||||
const v_int32 Server::STATUS_DONE = 4;
|
||||
|
||||
Server::Server(const std::shared_ptr<ServerConnectionProvider> &connectionProvider,
|
||||
Server::Server(const std::shared_ptr<ConnectionProvider> &connectionProvider,
|
||||
const std::shared_ptr<ConnectionHandler> &connectionHandler)
|
||||
: m_status(STATUS_CREATED)
|
||||
, m_connectionProvider(connectionProvider)
|
||||
@ -45,21 +44,20 @@ Server::Server(const std::shared_ptr<ServerConnectionProvider> &connectionProvid
|
||||
|
||||
// This isn't implemented as static since threading is dropped and therefore static isn't needed anymore.
|
||||
void Server::conditionalMainLoop() {
|
||||
|
||||
setStatus(STATUS_STARTING, STATUS_RUNNING);
|
||||
std::shared_ptr<const std::unordered_map<oatpp::String, oatpp::String>> params;
|
||||
|
||||
while (getStatus() == STATUS_RUNNING) {
|
||||
|
||||
if (m_condition()) {
|
||||
std::shared_ptr<data::stream::IOStream> connection;
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(m_spinlock);
|
||||
connection = m_connectionProvider->get();
|
||||
}
|
||||
if (connection) {
|
||||
|
||||
auto connectionHandle = m_connectionProvider->get();
|
||||
|
||||
if (connectionHandle.object) {
|
||||
if (getStatus() == STATUS_RUNNING) {
|
||||
if (m_condition()) {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(m_spinlock);
|
||||
m_connectionHandler->handleConnection(connection, params /* null params */);
|
||||
m_connectionHandler->handleConnection(connectionHandle, params /* null params */);
|
||||
} else {
|
||||
setStatus(STATUS_STOPPING);
|
||||
}
|
||||
@ -67,6 +65,7 @@ void Server::conditionalMainLoop() {
|
||||
OATPP_LOGD("[oatpp::network::server::mainLoop()]", "Error. Server already stopped - closing connection...");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
setStatus(STATUS_STOPPING);
|
||||
}
|
||||
@ -75,27 +74,23 @@ void Server::conditionalMainLoop() {
|
||||
}
|
||||
|
||||
void Server::mainLoop(Server *instance) {
|
||||
|
||||
instance->setStatus(STATUS_STARTING, STATUS_RUNNING);
|
||||
std::shared_ptr<const std::unordered_map<oatpp::String, oatpp::String>> params;
|
||||
|
||||
while (instance->getStatus() == STATUS_RUNNING) {
|
||||
std::shared_ptr<data::stream::IOStream> connection;
|
||||
{
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(instance->m_spinlock);
|
||||
connection = instance->m_connectionProvider->get();
|
||||
}
|
||||
while (instance->getStatus() == STATUS_RUNNING) {
|
||||
|
||||
if (connection) {
|
||||
auto connectionHandle = instance->m_connectionProvider->get();
|
||||
|
||||
if (connectionHandle) {
|
||||
if (instance->getStatus() == STATUS_RUNNING) {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(instance->m_spinlock);
|
||||
instance->m_connectionHandler->handleConnection(connection, params /* null params */);
|
||||
instance->m_connectionHandler->handleConnection(connectionHandle, params /* null params */);
|
||||
} else {
|
||||
OATPP_LOGD("[oatpp::network::server::mainLoop()]", "Error. Server already stopped - closing connection...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
instance->setStatus(STATUS_DONE);
|
||||
|
||||
}
|
||||
@ -172,16 +167,6 @@ v_int32 Server::getStatus() {
|
||||
return m_status.load();
|
||||
}
|
||||
|
||||
void Server::setConnectionProvider(const std::shared_ptr<ServerConnectionProvider> &connectionProvider) {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(m_spinlock);
|
||||
m_connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
void Server::setConnectionHandler(const std::shared_ptr<ConnectionHandler> &connectionHandler) {
|
||||
std::lock_guard<oatpp::concurrency::SpinLock> lg(m_spinlock);
|
||||
m_connectionHandler = connectionHandler;
|
||||
}
|
||||
|
||||
Server::~Server() {
|
||||
stop();
|
||||
}
|
||||
|
@ -58,9 +58,8 @@ private:
|
||||
std::function<bool()> m_condition;
|
||||
std::thread m_thread;
|
||||
std::mutex m_mutex;
|
||||
oatpp::concurrency::SpinLock m_spinlock;
|
||||
|
||||
std::shared_ptr<ServerConnectionProvider> m_connectionProvider;
|
||||
std::shared_ptr<ConnectionProvider> m_connectionProvider;
|
||||
std::shared_ptr<ConnectionHandler> m_connectionHandler;
|
||||
|
||||
bool m_threaded;
|
||||
@ -72,7 +71,7 @@ public:
|
||||
* @param connectionProvider - &id:oatpp::network::ConnectionProvider;.
|
||||
* @param connectionHandler - &id:oatpp::network::ConnectionHandler;.
|
||||
*/
|
||||
Server(const std::shared_ptr<ServerConnectionProvider>& connectionProvider,
|
||||
Server(const std::shared_ptr<ConnectionProvider>& connectionProvider,
|
||||
const std::shared_ptr<ConnectionHandler>& connectionHandler);
|
||||
|
||||
virtual ~Server();
|
||||
@ -156,21 +155,8 @@ public:
|
||||
*/
|
||||
v_int32 getStatus();
|
||||
|
||||
/**
|
||||
* Replaces the internal connection-provider
|
||||
* @param connectionProvider - &id:oatpp::network::ConnectionProvider;.
|
||||
*/
|
||||
void setConnectionProvider(const std::shared_ptr<ServerConnectionProvider>& connectionProvider);
|
||||
|
||||
/**
|
||||
* Replaces the internal connection-handler
|
||||
* @param connectionHandler - &id:oatpp::network::ConnectionHandler;.
|
||||
*/
|
||||
void setConnectionHandler(const std::shared_ptr<ConnectionHandler>& connectionHandler);
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* oatpp_network_Server_hpp */
|
||||
|
@ -35,15 +35,15 @@ 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);
|
||||
oatpp::base::StrBuffer::lowerCase(buff.get(), size);
|
||||
return oatpp::String((const char*)buff.get(), size, true);
|
||||
utils::String::lowerCase_ASCII(buff.get(), size);
|
||||
return oatpp::String((const char*)buff.get(), size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Url::Authority Url::Parser::parseAuthority(oatpp::parser::Caret& caret) {
|
||||
|
||||
p_char8 data = caret.getData();
|
||||
const char* data = caret.getData();
|
||||
v_buff_size pos0 = caret.getPosition();
|
||||
v_buff_size pos = pos0;
|
||||
|
||||
@ -75,11 +75,11 @@ Url::Authority Url::Parser::parseAuthority(oatpp::parser::Caret& caret) {
|
||||
Url::Authority result;
|
||||
|
||||
if(atPos > -1) {
|
||||
result.userInfo = oatpp::String((const char*)&data[pos0], atPos - pos0, true);
|
||||
result.userInfo = oatpp::String((const char*)&data[pos0], atPos - pos0);
|
||||
}
|
||||
|
||||
if(portPos > hostPos) {
|
||||
result.host = oatpp::String((const char*)&data[hostPos], portPos - 1 - hostPos, true);
|
||||
result.host = oatpp::String((const char*)&data[hostPos], portPos - 1 - hostPos);
|
||||
char* end;
|
||||
result.port = std::strtol((const char*)&data[portPos], &end, 10);
|
||||
bool success = (((v_buff_size)end - (v_buff_size)&data[portPos]) == pos - portPos);
|
||||
@ -87,7 +87,7 @@ Url::Authority Url::Parser::parseAuthority(oatpp::parser::Caret& caret) {
|
||||
caret.setError("Invalid port string");
|
||||
}
|
||||
} else {
|
||||
result.host = oatpp::String((const char*)&data[hostPos], pos - pos0, true);
|
||||
result.host = oatpp::String((const char*)&data[hostPos], pos - pos0);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -96,9 +96,9 @@ Url::Authority Url::Parser::parseAuthority(oatpp::parser::Caret& caret) {
|
||||
|
||||
oatpp::String Url::Parser::parsePath(oatpp::parser::Caret& caret) {
|
||||
auto label = caret.putLabel();
|
||||
caret.findCharFromSet((p_char8)"?#", 2);
|
||||
caret.findCharFromSet("?#", 2);
|
||||
if(label.getSize() > 0) {
|
||||
return label.toString(true);
|
||||
return label.toString();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -156,7 +156,7 @@ Url Url::Parser::parseUrl(oatpp::parser::Caret& caret) {
|
||||
caret.setPosition(0);
|
||||
}
|
||||
|
||||
caret.isAtText((p_char8)"//", 2, true);
|
||||
caret.isAtText("//", 2, true);
|
||||
|
||||
if(!caret.isAtChar('/')) {
|
||||
result.authority = parseAuthority(caret);
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include "oatpp/core/data/share/LazyStringMap.hpp"
|
||||
#include "oatpp/core/parser/Caret.hpp"
|
||||
#include "oatpp/core/collection/ListMap.hpp"
|
||||
#include "oatpp/core/Types.hpp"
|
||||
|
||||
namespace oatpp { namespace network {
|
||||
|
49
src/oatpp/network/monitor/ConnectionInactivityChecker.cpp
Normal file
49
src/oatpp/network/monitor/ConnectionInactivityChecker.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ConnectionInactivityChecker.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
ConnectionInactivityChecker::ConnectionInactivityChecker(const std::chrono::duration<v_int64, std::micro>& lastReadTimeout,
|
||||
const std::chrono::duration<v_int64, std::micro>& lastWriteTimeout)
|
||||
: m_lastReadTimeout(lastReadTimeout)
|
||||
, m_lastWriteTimeout(lastWriteTimeout)
|
||||
{}
|
||||
|
||||
std::vector<oatpp::String> ConnectionInactivityChecker::getMetricsList() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<StatCollector> ConnectionInactivityChecker::createStatCollector(const oatpp::String& metricName) {
|
||||
throw std::runtime_error("[oatpp::network::monitor::ConnectionInactivityChecker::createStatCollector()]: "
|
||||
"Error. ConnectionInactivityChecker doesn't use any stat collectors.");
|
||||
}
|
||||
|
||||
bool ConnectionInactivityChecker::check(const ConnectionStats& stats, v_int64 currMicroTime) {
|
||||
return currMicroTime - stats.timestampLastRead < m_lastReadTimeout.count() &&
|
||||
currMicroTime - stats.timestampLastWrite < m_lastWriteTimeout.count();
|
||||
}
|
||||
|
||||
}}}
|
60
src/oatpp/network/monitor/ConnectionInactivityChecker.hpp
Normal file
60
src/oatpp/network/monitor/ConnectionInactivityChecker.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_monitor_ConnectionInactivityChecker_hpp
|
||||
#define oatpp_network_monitor_ConnectionInactivityChecker_hpp
|
||||
|
||||
#include "MetricsChecker.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
/**
|
||||
* ConnectionInactivityChecker - checks if a connection is inactive (has no read/writes) and whether it should be closed.
|
||||
* Extends - &id:oatpp::network::monitor::MetricsChecker;.
|
||||
*/
|
||||
class ConnectionInactivityChecker : public MetricsChecker {
|
||||
private:
|
||||
std::chrono::duration<v_int64, std::micro> m_lastReadTimeout;
|
||||
std::chrono::duration<v_int64, std::micro> m_lastWriteTimeout;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param lastReadTimeout - how long can live connection without reads.
|
||||
* @param lastWriteTimeout - how long can live connection without writes.
|
||||
*/
|
||||
ConnectionInactivityChecker(const std::chrono::duration<v_int64, std::micro>& lastReadTimeout,
|
||||
const std::chrono::duration<v_int64, std::micro>& lastWriteTimeout);
|
||||
|
||||
std::vector<oatpp::String> getMetricsList();
|
||||
|
||||
std::shared_ptr<StatCollector> createStatCollector(const oatpp::String& metricName);
|
||||
|
||||
bool check(const ConnectionStats& stats, v_int64 currMicroTime);
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_network_monitor_ConnectionInactivityChecker_hpp
|
46
src/oatpp/network/monitor/ConnectionMaxAgeChecker.cpp
Normal file
46
src/oatpp/network/monitor/ConnectionMaxAgeChecker.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ConnectionMaxAgeChecker.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
ConnectionMaxAgeChecker::ConnectionMaxAgeChecker(const std::chrono::duration<v_int64, std::micro>& maxAge)
|
||||
: m_maxAge(maxAge)
|
||||
{}
|
||||
|
||||
std::vector<oatpp::String> ConnectionMaxAgeChecker::getMetricsList() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<StatCollector> ConnectionMaxAgeChecker::createStatCollector(const oatpp::String& metricName) {
|
||||
throw std::runtime_error("[oatpp::network::monitor::ConnectionMaxAgeChecker::createStatCollector()]: "
|
||||
"Error. ConnectionMaxAgeChecker doesn't use any stat collectors.");
|
||||
}
|
||||
|
||||
bool ConnectionMaxAgeChecker::check(const ConnectionStats& stats, v_int64 currMicroTime) {
|
||||
return currMicroTime - stats.timestampCreated < m_maxAge.count();
|
||||
}
|
||||
|
||||
}}}
|
57
src/oatpp/network/monitor/ConnectionMaxAgeChecker.hpp
Normal file
57
src/oatpp/network/monitor/ConnectionMaxAgeChecker.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_monitor_ConnectionMaxAgeChecker_hpp
|
||||
#define oatpp_network_monitor_ConnectionMaxAgeChecker_hpp
|
||||
|
||||
#include "MetricsChecker.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
/**
|
||||
* ConnectionMaxAgeChecker - checks if connection is too old and should be closed.
|
||||
* Extends - &id:oatpp::network::monitor::MetricsChecker;.
|
||||
*/
|
||||
class ConnectionMaxAgeChecker : public MetricsChecker {
|
||||
private:
|
||||
std::chrono::duration<v_int64, std::micro> m_maxAge;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxAge - how long should connection live.
|
||||
*/
|
||||
ConnectionMaxAgeChecker(const std::chrono::duration<v_int64, std::micro>& maxAge);
|
||||
|
||||
std::vector<oatpp::String> getMetricsList();
|
||||
|
||||
std::shared_ptr<StatCollector> createStatCollector(const oatpp::String& metricName);
|
||||
|
||||
bool check(const ConnectionStats& stats, v_int64 currMicroTime);
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_network_monitor_ConnectionMaxAgeChecker_hpp
|
338
src/oatpp/network/monitor/ConnectionMonitor.cpp
Normal file
338
src/oatpp/network/monitor/ConnectionMonitor.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ConnectionMonitor.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionMonitor::ConnectionInvalidator
|
||||
|
||||
void ConnectionMonitor::ConnectionInvalidator::invalidate(const std::shared_ptr<data::stream::IOStream> &connection) {
|
||||
auto proxy = std::static_pointer_cast<ConnectionProxy>(connection);
|
||||
proxy->invalidate();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionMonitor::ConnectionProxy
|
||||
|
||||
ConnectionMonitor::ConnectionProxy::ConnectionProxy(const std::shared_ptr<Monitor>& monitor,
|
||||
const provider::ResourceHandle<data::stream::IOStream>& connectionHandle)
|
||||
: m_monitor(monitor)
|
||||
, m_connectionHandle(connectionHandle)
|
||||
{
|
||||
m_stats.timestampCreated = base::Environment::getMicroTickCount();
|
||||
}
|
||||
|
||||
ConnectionMonitor::ConnectionProxy::~ConnectionProxy() {
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_statsMutex);
|
||||
|
||||
m_monitor->freeConnectionStats(m_stats);
|
||||
|
||||
if(m_stats.metricsData.size() > 0) {
|
||||
|
||||
for(auto& pair : m_stats.metricsData) {
|
||||
OATPP_LOGE("[oatpp::network::ConnectionMonitor::ConnectionProxy::~ConnectionProxy()]",
|
||||
"Error. Memory leak. Metric data was not deleted: Metric name - '%s'", pair.first->c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_monitor->removeConnection((v_uint64) this);
|
||||
|
||||
}
|
||||
|
||||
v_io_size ConnectionMonitor::ConnectionProxy::read(void *buffer, v_buff_size count, async::Action& action) {
|
||||
auto res = m_connectionHandle.object->read(buffer, count, action);
|
||||
std::lock_guard<std::mutex> lock(m_statsMutex);
|
||||
m_monitor->onConnectionRead(m_stats, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
v_io_size ConnectionMonitor::ConnectionProxy::write(const void *data, v_buff_size count, async::Action& action) {
|
||||
auto res = m_connectionHandle.object->write(data, count, action);
|
||||
std::lock_guard<std::mutex> lock(m_statsMutex);
|
||||
m_monitor->onConnectionWrite(m_stats, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void ConnectionMonitor::ConnectionProxy::setInputStreamIOMode(data::stream::IOMode ioMode) {
|
||||
m_connectionHandle.object->setInputStreamIOMode(ioMode);
|
||||
}
|
||||
data::stream::IOMode ConnectionMonitor::ConnectionProxy::getInputStreamIOMode() {
|
||||
return m_connectionHandle.object->getInputStreamIOMode();
|
||||
}
|
||||
data::stream::Context& ConnectionMonitor::ConnectionProxy::getInputStreamContext() {
|
||||
return m_connectionHandle.object->getInputStreamContext();
|
||||
}
|
||||
|
||||
void ConnectionMonitor::ConnectionProxy::setOutputStreamIOMode(data::stream::IOMode ioMode) {
|
||||
m_connectionHandle.object->setOutputStreamIOMode(ioMode);
|
||||
}
|
||||
|
||||
data::stream::IOMode ConnectionMonitor::ConnectionProxy::getOutputStreamIOMode() {
|
||||
return m_connectionHandle.object->getOutputStreamIOMode();
|
||||
}
|
||||
|
||||
data::stream::Context& ConnectionMonitor::ConnectionProxy::getOutputStreamContext() {
|
||||
return m_connectionHandle.object->getOutputStreamContext();
|
||||
}
|
||||
|
||||
void ConnectionMonitor::ConnectionProxy::invalidate() {
|
||||
m_connectionHandle.invalidator->invalidate(m_connectionHandle.object);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Monitor
|
||||
|
||||
void ConnectionMonitor::Monitor::monitorTask(std::shared_ptr<Monitor> monitor) {
|
||||
|
||||
while(monitor->m_running) {
|
||||
|
||||
{
|
||||
|
||||
std::lock_guard<std::mutex> lock(monitor->m_connectionsMutex);
|
||||
|
||||
auto currMicroTime = oatpp::base::Environment::getMicroTickCount();
|
||||
|
||||
for(auto& pair : monitor->m_connections) {
|
||||
|
||||
auto connection = pair.second.lock();
|
||||
std::lock_guard<std::mutex> dataLock(connection->m_statsMutex);
|
||||
std::lock_guard<std::mutex> analysersLock(monitor->m_checkMutex);
|
||||
|
||||
for(auto& a : monitor->m_metricsCheckers) {
|
||||
bool res = a->check(connection->m_stats, currMicroTime);
|
||||
if(!res) {
|
||||
connection->invalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex>(monitor->m_runMutex);
|
||||
monitor->m_stopped = true;
|
||||
}
|
||||
|
||||
monitor->m_runCondition.notify_all();
|
||||
|
||||
}
|
||||
|
||||
void* ConnectionMonitor::Monitor::createOrGetMetricData(ConnectionStats& stats, const std::shared_ptr<StatCollector>& collector) {
|
||||
void* data;
|
||||
auto it = stats.metricsData.find(collector->metricName());
|
||||
if(it == stats.metricsData.end()) {
|
||||
data = collector->createMetricData();
|
||||
stats.metricsData.insert({collector->metricName(), data});
|
||||
} else {
|
||||
data = it->second;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::shared_ptr<ConnectionMonitor::Monitor> ConnectionMonitor::Monitor::createShared() {
|
||||
auto monitor = std::make_shared<Monitor>();
|
||||
std::thread t([monitor](){
|
||||
ConnectionMonitor::Monitor::monitorTask(monitor);
|
||||
});
|
||||
t.detach();
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::addConnection(v_uint64 id, const std::weak_ptr<ConnectionProxy>& connection) {
|
||||
std::lock_guard<std::mutex> lock(m_connectionsMutex);
|
||||
m_connections.insert({id, connection});
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::freeConnectionStats(ConnectionStats& stats) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
|
||||
for(auto& metric : stats.metricsData) {
|
||||
auto it = m_statCollectors.find(metric.first);
|
||||
if(it != m_statCollectors.end()) {
|
||||
it->second->deleteMetricData(metric.second);
|
||||
} else {
|
||||
OATPP_LOGE("[oatpp::network::ConnectionMonitor::Monitor::freeConnectionStats]",
|
||||
"Error. Can't free Metric data. Unknown Metric: name - '%s'", it->first->c_str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::removeConnection(v_uint64 id) {
|
||||
std::lock_guard<std::mutex> lock(m_connectionsMutex);
|
||||
m_connections.erase(id);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::addStatCollector(const std::shared_ptr<StatCollector>& collector) {
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
m_statCollectors.insert({collector->metricName(), collector});
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::removeStatCollector(const oatpp::String& metricName) {
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
m_statCollectors.erase(metricName);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::addMetricsChecker(const std::shared_ptr<MetricsChecker>& checker) {
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
m_metricsCheckers.push_back(checker);
|
||||
auto metrics = checker->getMetricsList();
|
||||
for(auto& m : metrics) {
|
||||
auto it = m_statCollectors.find(m);
|
||||
if(it == m_statCollectors.end()) {
|
||||
m_statCollectors.insert({m, checker->createStatCollector(m)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::onConnectionRead(ConnectionStats& stats, v_io_size readResult) {
|
||||
|
||||
v_int64 currTimestamp = base::Environment::getMicroTickCount();
|
||||
|
||||
if(readResult > 0) {
|
||||
stats.totalRead += readResult;
|
||||
stats.lastReadSize = readResult;
|
||||
stats.timestampLastRead = currTimestamp;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
for(auto& pair : m_statCollectors) {
|
||||
pair.second->onRead(createOrGetMetricData(stats, pair.second), readResult, currTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::onConnectionWrite(ConnectionStats& stats, v_io_size writeResult) {
|
||||
|
||||
v_int64 currTimestamp = base::Environment::getMicroTickCount();
|
||||
|
||||
if(writeResult > 0) {
|
||||
stats.totalWrite += writeResult;
|
||||
stats.lastWriteSize = writeResult;
|
||||
stats.timestampLastWrite = currTimestamp;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_checkMutex);
|
||||
for(auto& pair : m_statCollectors) {
|
||||
pair.second->onWrite(createOrGetMetricData(stats, pair.second), writeResult, currTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionMonitor::Monitor::stop() {
|
||||
m_running = false;
|
||||
std::unique_lock<std::mutex> runLock(m_runMutex);
|
||||
while(!m_stopped) {
|
||||
m_runCondition.wait(runLock);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionMonitor
|
||||
|
||||
ConnectionMonitor::ConnectionMonitor(const std::shared_ptr<ConnectionProvider>& connectionProvider)
|
||||
: m_invalidator(std::make_shared<ConnectionInvalidator>())
|
||||
, m_monitor(Monitor::createShared())
|
||||
, m_connectionProvider(connectionProvider)
|
||||
{
|
||||
}
|
||||
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionMonitor::get() {
|
||||
auto connection = m_connectionProvider->get();
|
||||
if(!connection) {
|
||||
return nullptr;
|
||||
}
|
||||
auto proxy = std::make_shared<ConnectionProxy>(m_monitor, connection);
|
||||
m_monitor->addConnection((v_uint64) proxy.get(), proxy);
|
||||
return provider::ResourceHandle<data::stream::IOStream>(proxy, m_invalidator);
|
||||
}
|
||||
|
||||
async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&>
|
||||
ConnectionMonitor::getAsync() {
|
||||
|
||||
class GetConnectionCoroutine : public async::CoroutineWithResult<GetConnectionCoroutine, const provider::ResourceHandle<data::stream::IOStream>&> {
|
||||
private:
|
||||
std::shared_ptr<Monitor> m_monitor;
|
||||
std::shared_ptr<ConnectionProvider> m_connectionProvider;
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
public:
|
||||
|
||||
GetConnectionCoroutine(const std::shared_ptr<Monitor>& monitor,
|
||||
const std::shared_ptr<ConnectionProvider>& connectionProvider,
|
||||
const std::shared_ptr<ConnectionInvalidator>& invalidator)
|
||||
: m_monitor(monitor)
|
||||
, m_connectionProvider(connectionProvider)
|
||||
, m_invalidator(invalidator)
|
||||
{}
|
||||
|
||||
Action act() override {
|
||||
return m_connectionProvider->getAsync().callbackTo(&GetConnectionCoroutine::onConnection);
|
||||
}
|
||||
|
||||
Action onConnection(const provider::ResourceHandle<data::stream::IOStream>& connection) {
|
||||
if(!connection) {
|
||||
return _return(nullptr);
|
||||
}
|
||||
auto proxy = std::make_shared<ConnectionProxy>(m_monitor, connection);
|
||||
m_monitor->addConnection((v_uint64) proxy.get(), proxy);
|
||||
return _return(provider::ResourceHandle<data::stream::IOStream>(proxy, m_invalidator));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return GetConnectionCoroutine::startForResult(m_monitor, m_connectionProvider, m_invalidator);
|
||||
|
||||
}
|
||||
|
||||
void ConnectionMonitor::addStatCollector(const std::shared_ptr<StatCollector>& collector) {
|
||||
m_monitor->addStatCollector(collector);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::addMetricsChecker(const std::shared_ptr<MetricsChecker>& checker) {
|
||||
m_monitor->addMetricsChecker(checker);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::stop() {
|
||||
m_monitor->stop();
|
||||
}
|
||||
|
||||
}}}
|
156
src/oatpp/network/monitor/ConnectionMonitor.hpp
Normal file
156
src/oatpp/network/monitor/ConnectionMonitor.hpp
Normal file
@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_monitor_ConnectionMonitor_hpp
|
||||
#define oatpp_network_monitor_ConnectionMonitor_hpp
|
||||
|
||||
#include "MetricsChecker.hpp"
|
||||
|
||||
#include "oatpp/network/ConnectionProvider.hpp"
|
||||
#include "oatpp/core/data/stream/Stream.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
/**
|
||||
* ConnectionMonitor is a middleman who's able to manage provided connections
|
||||
* and close those ones that are not satisfy selected rules.
|
||||
*/
|
||||
class ConnectionMonitor : public ClientConnectionProvider, public ServerConnectionProvider {
|
||||
private:
|
||||
|
||||
class ConnectionInvalidator : public provider::Invalidator<data::stream::IOStream> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class Monitor; // FWD
|
||||
|
||||
class ConnectionProxy : public data::stream::IOStream {
|
||||
friend Monitor;
|
||||
private:
|
||||
std::shared_ptr<Monitor> m_monitor;
|
||||
provider::ResourceHandle<data::stream::IOStream> m_connectionHandle;
|
||||
std::mutex m_statsMutex;
|
||||
ConnectionStats m_stats;
|
||||
public:
|
||||
|
||||
ConnectionProxy(const std::shared_ptr<Monitor>& monitor,
|
||||
const provider::ResourceHandle<data::stream::IOStream>& connectionHandle);
|
||||
|
||||
~ConnectionProxy() override;
|
||||
|
||||
v_io_size read(void *buffer, v_buff_size count, async::Action& action) override;
|
||||
v_io_size write(const void *data, v_buff_size count, async::Action& action) override;
|
||||
|
||||
void setInputStreamIOMode(data::stream::IOMode ioMode) override;
|
||||
data::stream::IOMode getInputStreamIOMode() override;
|
||||
data::stream::Context& getInputStreamContext() override;
|
||||
|
||||
void setOutputStreamIOMode(data::stream::IOMode ioMode) override;
|
||||
data::stream::IOMode getOutputStreamIOMode() override;
|
||||
data::stream::Context& getOutputStreamContext() override;
|
||||
|
||||
void invalidate();
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class Monitor : public oatpp::base::Countable {
|
||||
private:
|
||||
|
||||
std::mutex m_runMutex;
|
||||
std::condition_variable m_runCondition;
|
||||
std::atomic<bool> m_running {true};
|
||||
bool m_stopped {false};
|
||||
|
||||
std::mutex m_connectionsMutex;
|
||||
std::unordered_map<v_uint64, std::weak_ptr<ConnectionProxy>> m_connections;
|
||||
|
||||
std::mutex m_checkMutex;
|
||||
std::vector<std::shared_ptr<MetricsChecker>> m_metricsCheckers;
|
||||
std::unordered_map<oatpp::String, std::shared_ptr<StatCollector>> m_statCollectors;
|
||||
|
||||
private:
|
||||
static void monitorTask(std::shared_ptr<Monitor> monitor);
|
||||
private:
|
||||
static void* createOrGetMetricData(ConnectionStats& stats, const std::shared_ptr<StatCollector>& collector);
|
||||
public:
|
||||
|
||||
static std::shared_ptr<Monitor> createShared();
|
||||
|
||||
void addConnection(v_uint64 id, const std::weak_ptr<ConnectionProxy>& connection);
|
||||
void freeConnectionStats(ConnectionStats& stats);
|
||||
void removeConnection(v_uint64 id);
|
||||
|
||||
void addStatCollector(const std::shared_ptr<StatCollector>& collector);
|
||||
void removeStatCollector(const oatpp::String& metricName);
|
||||
|
||||
void addMetricsChecker(const std::shared_ptr<MetricsChecker>& checker);
|
||||
|
||||
void onConnectionRead(ConnectionStats& stats, v_io_size readResult);
|
||||
void onConnectionWrite(ConnectionStats& stats, v_io_size writeResult);
|
||||
|
||||
void stop();
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
std::shared_ptr<Monitor> m_monitor;
|
||||
std::shared_ptr<ConnectionProvider> m_connectionProvider;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param connectionProvider - underlying connection provider.
|
||||
*/
|
||||
ConnectionMonitor(const std::shared_ptr<ConnectionProvider>& connectionProvider);
|
||||
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
void addStatCollector(const std::shared_ptr<StatCollector>& collector);
|
||||
|
||||
/**
|
||||
* Add metrics checker.
|
||||
* @param checker - &id:oatpp::network::monitor::MetricsChecker;.
|
||||
*/
|
||||
void addMetricsChecker(const std::shared_ptr<MetricsChecker>& checker);
|
||||
|
||||
void stop() override;
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_network_monitor_ConnectionMonitor_hpp
|
71
src/oatpp/network/monitor/MetricsChecker.hpp
Normal file
71
src/oatpp/network/monitor/MetricsChecker.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_monitor_MetricsChecker_hpp
|
||||
#define oatpp_network_monitor_MetricsChecker_hpp
|
||||
|
||||
#include "StatCollector.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
/**
|
||||
* MetricsChecker checks &id:oatpp::network::monitor::ConnectionStats; if those are satisfy the rule.
|
||||
*/
|
||||
class MetricsChecker : public oatpp::base::Countable {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default virtual destructor.
|
||||
*/
|
||||
virtual ~MetricsChecker() = default;
|
||||
|
||||
/**
|
||||
* Get list of metrics names that are checked by this MetricsChecker.
|
||||
* @return
|
||||
*/
|
||||
virtual std::vector<oatpp::String> getMetricsList() = 0;
|
||||
|
||||
/**
|
||||
* Create &id:oatpp::network::monitor::StatCollector; for given `metricName`.
|
||||
* This method will be called by &id:oatpp::network::monitor::ConnectionMonitor; only if there is
|
||||
* no such `StatCollector` registered in the `ConnectionMonitor` yet.
|
||||
* @param metricName - name of the metric.
|
||||
* @return - &id:oatpp::network::monitor::StatCollector;.
|
||||
*/
|
||||
virtual std::shared_ptr<StatCollector> createStatCollector(const oatpp::String& metricName) = 0;
|
||||
|
||||
/**
|
||||
* Called by &id:oatpp::network::monitor::ConnectionMonitor; on each
|
||||
* time interval to check if connection satisfies the rule.
|
||||
* @param stats - &id:oatpp::network::monitor::ConnectionStats;.
|
||||
* @param currMicroTime - current time microseconds.
|
||||
* @return - `true` if connection satisfies the rule. `false` if connection should be closed.
|
||||
*/
|
||||
virtual bool check(const ConnectionStats& stats, v_int64 currMicroTime) = 0;
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_network_monitor_MetricsChecker_hpp
|
131
src/oatpp/network/monitor/StatCollector.hpp
Normal file
131
src/oatpp/network/monitor/StatCollector.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_monitor_StatCollector_hpp
|
||||
#define oatpp_network_monitor_StatCollector_hpp
|
||||
|
||||
#include "oatpp/core/Types.hpp"
|
||||
#include "oatpp/core/IODefinitions.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace monitor {
|
||||
|
||||
/**
|
||||
* ConnectionStats.
|
||||
*/
|
||||
struct ConnectionStats {
|
||||
|
||||
/**
|
||||
* Timestamp created microseconds.
|
||||
* When connection was created.
|
||||
*/
|
||||
v_int64 timestampCreated = 0;
|
||||
|
||||
/**
|
||||
* Total bytes read from the connection.
|
||||
* Logs all bytes when the `read` method is called.
|
||||
*/
|
||||
v_io_size totalRead = 0;
|
||||
|
||||
/**
|
||||
* Total bytes written to the connection.
|
||||
* Logs all bytes when the `write` method is called.
|
||||
*/
|
||||
v_io_size totalWrite = 0;
|
||||
|
||||
/**
|
||||
* Timestamp microseconds when the last successful read was performed on the connection.
|
||||
*/
|
||||
v_int64 timestampLastRead = 0;
|
||||
|
||||
/**
|
||||
* Timestamp microseconds when the last successful write was performed on the connection.
|
||||
*/
|
||||
v_int64 timestampLastWrite = 0;
|
||||
|
||||
/**
|
||||
* Amount of bytes read during the last successful read.
|
||||
*/
|
||||
v_io_size lastReadSize = 0;
|
||||
|
||||
/**
|
||||
* Amount of bytes written during the last successful write.
|
||||
*/
|
||||
v_io_size lastWriteSize = 0;
|
||||
|
||||
/**
|
||||
* Data collected by stat-collectors - &l:StatCollector;
|
||||
*/
|
||||
std::unordered_map<oatpp::String, void*> metricsData;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* StatCollector collects metrics data of the connection.
|
||||
*/
|
||||
class StatCollector : public oatpp::base::Countable {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default virtual destructor.
|
||||
*/
|
||||
virtual ~StatCollector() = default;
|
||||
|
||||
/**
|
||||
* Unique metric name that is collected by this `StatCollector`.
|
||||
* @return - metricName. &id:oatpp::String;.
|
||||
*/
|
||||
virtual oatpp::String metricName() = 0;
|
||||
|
||||
/**
|
||||
* Metric data constructor.
|
||||
* @return
|
||||
*/
|
||||
virtual void* createMetricData() = 0;
|
||||
|
||||
/**
|
||||
* Metric data destructor.
|
||||
* @param metricData
|
||||
*/
|
||||
virtual void deleteMetricData(void* metricData) = 0;
|
||||
|
||||
/**
|
||||
* On connection read event.
|
||||
* @param metricData - metric data of the given connection.- the one created in the `createMetricData` method.
|
||||
* @param readResult - result of the connection read method.
|
||||
* @param timestamp - timestamp microseconds when the connection `read` method was called.
|
||||
*/
|
||||
virtual void onRead(void* metricData, v_io_size readResult, v_int64 timestamp) = 0;
|
||||
|
||||
/**
|
||||
* On connection write event.
|
||||
* @param metricData - metric data of the given connection.- the one created in the `createMetricData` method.
|
||||
* @param writeResult - result of the connection write method.
|
||||
* @param timestamp - timestamp microseconds when the connection `write` method was called.
|
||||
*/
|
||||
virtual void onWrite(void* metricData, v_io_size writeResult, v_int64 timestamp) = 0;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_network_monitor_StatCollector_hpp
|
@ -42,14 +42,40 @@
|
||||
|
||||
namespace oatpp { namespace network { namespace tcp { namespace client {
|
||||
|
||||
void ConnectionProvider::ConnectionInvalidator::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
|
||||
/************************************************
|
||||
* WARNING!!!
|
||||
*
|
||||
* shutdown(handle, SHUT_RDWR) <--- DO!
|
||||
* close(handle); <--- DO NOT!
|
||||
*
|
||||
* DO NOT CLOSE file handle here -
|
||||
* USE shutdown instead.
|
||||
* Using close prevent FDs popping out of epoll,
|
||||
* and they'll be stuck there forever.
|
||||
************************************************/
|
||||
|
||||
auto c = std::static_pointer_cast<network::tcp::Connection>(connection);
|
||||
v_io_handle handle = c->getHandle();
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
shutdown(handle, SD_BOTH);
|
||||
#else
|
||||
shutdown(handle, SHUT_RDWR);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
ConnectionProvider::ConnectionProvider(const network::Address& address)
|
||||
: m_address(address)
|
||||
: m_invalidator(std::make_shared<ConnectionInvalidator>())
|
||||
, m_address(address)
|
||||
{
|
||||
setProperty(PROPERTY_HOST, address.host);
|
||||
setProperty(PROPERTY_PORT, oatpp::utils::conversion::int32ToStr(address.port));
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::get() {
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProvider::get() {
|
||||
|
||||
auto portStr = oatpp::utils::conversion::int32ToStr(m_address.port);
|
||||
|
||||
@ -123,14 +149,18 @@ std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::get() {
|
||||
}
|
||||
#endif
|
||||
|
||||
return std::make_shared<oatpp::network::tcp::Connection>(clientHandle);
|
||||
return provider::ResourceHandle<data::stream::IOStream>(
|
||||
std::make_shared<oatpp::network::tcp::Connection>(clientHandle),
|
||||
m_invalidator
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::stream::IOStream>&> ConnectionProvider::getAsync() {
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> ConnectionProvider::getAsync() {
|
||||
|
||||
class ConnectCoroutine : public oatpp::async::CoroutineWithResult<ConnectCoroutine, const std::shared_ptr<oatpp::data::stream::IOStream>&> {
|
||||
class ConnectCoroutine : public oatpp::async::CoroutineWithResult<ConnectCoroutine, const provider::ResourceHandle<oatpp::data::stream::IOStream>&> {
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_connectionInvalidator;
|
||||
network::Address m_address;
|
||||
oatpp::v_io_handle m_clientHandle;
|
||||
private:
|
||||
@ -139,8 +169,10 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
bool m_isHandleOpened;
|
||||
public:
|
||||
|
||||
ConnectCoroutine(const network::Address& address)
|
||||
: m_address(address)
|
||||
ConnectCoroutine(const std::shared_ptr<ConnectionInvalidator>& connectionInvalidator,
|
||||
const network::Address& address)
|
||||
: m_connectionInvalidator(connectionInvalidator)
|
||||
, m_address(address)
|
||||
, m_result(nullptr)
|
||||
, m_currentResult(nullptr)
|
||||
, m_isHandleOpened(false)
|
||||
@ -250,7 +282,10 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
auto error = WSAGetLastError();
|
||||
|
||||
if(res == 0 || error == WSAEISCONN) {
|
||||
return _return(std::make_shared<oatpp::network::tcp::Connection>(m_clientHandle));
|
||||
return _return(provider::ResourceHandle<data::stream::IOStream>(
|
||||
std::make_shared<oatpp::network::tcp::Connection>(m_clientHandle),
|
||||
m_connectionInvalidator
|
||||
));
|
||||
}
|
||||
if(error == WSAEWOULDBLOCK || error == WSAEINPROGRESS) {
|
||||
return ioWait(m_clientHandle, oatpp::async::Action::IOEventType::IO_EVENT_WRITE);
|
||||
@ -261,7 +296,10 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
#else
|
||||
|
||||
if(res == 0 || errno == EISCONN) {
|
||||
return _return(std::make_shared<oatpp::network::tcp::Connection>(m_clientHandle));
|
||||
return _return(provider::ResourceHandle<data::stream::IOStream>(
|
||||
std::make_shared<oatpp::network::tcp::Connection>(m_clientHandle),
|
||||
m_connectionInvalidator
|
||||
));
|
||||
}
|
||||
if(errno == EALREADY || errno == EINPROGRESS) {
|
||||
return ioWait(m_clientHandle, oatpp::async::Action::IOEventType::IO_EVENT_WRITE);
|
||||
@ -278,32 +316,7 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
|
||||
};
|
||||
|
||||
return ConnectCoroutine::startForResult(m_address);
|
||||
|
||||
}
|
||||
|
||||
void ConnectionProvider::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
|
||||
/************************************************
|
||||
* WARNING!!!
|
||||
*
|
||||
* shutdown(handle, SHUT_RDWR) <--- DO!
|
||||
* close(handle); <--- DO NOT!
|
||||
*
|
||||
* DO NOT CLOSE file handle here -
|
||||
* USE shutdown instead.
|
||||
* Using close prevent FDs popping out of epoll,
|
||||
* and they'll be stuck there forever.
|
||||
************************************************/
|
||||
|
||||
auto c = std::static_pointer_cast<network::tcp::Connection>(connection);
|
||||
v_io_handle handle = c->getHandle();
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
shutdown(handle, SD_BOTH);
|
||||
#else
|
||||
shutdown(handle, SHUT_RDWR);
|
||||
#endif
|
||||
return ConnectCoroutine::startForResult(m_invalidator, m_address);
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "oatpp/network/Address.hpp"
|
||||
|
||||
#include "oatpp/network/ConnectionProvider.hpp"
|
||||
#include "oatpp/core/provider/Invalidator.hpp"
|
||||
#include "oatpp/core/Types.hpp"
|
||||
|
||||
namespace oatpp { namespace network { namespace tcp { namespace client {
|
||||
@ -35,7 +36,18 @@ namespace oatpp { namespace network { namespace tcp { namespace client {
|
||||
/**
|
||||
* Simple provider of clinet TCP connections.
|
||||
*/
|
||||
class ConnectionProvider : public base::Countable, public ClientConnectionProvider {
|
||||
class ConnectionProvider : public ClientConnectionProvider {
|
||||
private:
|
||||
|
||||
class ConnectionInvalidator : public provider::Invalidator<data::stream::IOStream> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
protected:
|
||||
network::Address m_address;
|
||||
public:
|
||||
@ -66,20 +78,13 @@ public:
|
||||
* Get connection.
|
||||
* @return - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
std::shared_ptr<data::stream::IOStream> get() override;
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
/**
|
||||
* Get connection in asynchronous manner.
|
||||
* @return - &id:oatpp::async::CoroutineStarterForResult;.
|
||||
*/
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
/**
|
||||
* Call shutdown read and write on an underlying file descriptor.
|
||||
* `connection` **MUST** be an object previously obtained from **THIS** connection provider.
|
||||
* @param connection
|
||||
*/
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
/**
|
||||
* Get address - &id:oatpp::network::Address;.
|
||||
|
@ -90,11 +90,41 @@ oatpp::data::stream::Context& ConnectionProvider::ExtendedConnection::getInputSt
|
||||
return m_context;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionProvider::ConnectionInvalidator
|
||||
|
||||
void ConnectionProvider::ConnectionInvalidator::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
|
||||
/************************************************
|
||||
* WARNING!!!
|
||||
*
|
||||
* shutdown(handle, SHUT_RDWR) <--- DO!
|
||||
* close(handle); <--- DO NOT!
|
||||
*
|
||||
* DO NOT CLOSE file handle here -
|
||||
* USE shutdown instead.
|
||||
* Using close prevent FDs popping out of epoll,
|
||||
* and they'll be stuck there forever.
|
||||
************************************************/
|
||||
|
||||
auto c = std::static_pointer_cast<network::tcp::Connection>(connection);
|
||||
v_io_handle handle = c->getHandle();
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
shutdown(handle, SD_BOTH);
|
||||
#else
|
||||
shutdown(handle, SHUT_RDWR);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionProvider
|
||||
|
||||
ConnectionProvider::ConnectionProvider(const network::Address& address, bool useExtendedConnections)
|
||||
: m_address(address)
|
||||
: m_invalidator(std::make_shared<ConnectionInvalidator>())
|
||||
, m_address(address)
|
||||
, m_closed(false)
|
||||
, m_useExtendedConnections(useExtendedConnections)
|
||||
{
|
||||
@ -301,7 +331,7 @@ bool ConnectionProvider::prepareConnectionHandle(oatpp::v_io_handle handle) {
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::getDefaultConnection() {
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProvider::getDefaultConnection() {
|
||||
|
||||
oatpp::v_io_handle handle = accept(m_serverHandle, nullptr, nullptr);
|
||||
|
||||
@ -310,14 +340,17 @@ std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::getDefaultCon
|
||||
}
|
||||
|
||||
if(prepareConnectionHandle(handle)) {
|
||||
return std::make_shared<Connection>(handle);
|
||||
return provider::ResourceHandle<data::stream::IOStream>(
|
||||
std::make_shared<Connection>(handle),
|
||||
m_invalidator
|
||||
);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::getExtendedConnection() {
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProvider::getExtendedConnection() {
|
||||
|
||||
struct sockaddr_storage clientAddress;
|
||||
socklen_t clientAddressSize = sizeof(clientAddress);
|
||||
@ -364,14 +397,17 @@ std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::getExtendedCo
|
||||
}
|
||||
|
||||
if(prepareConnectionHandle(handle)) {
|
||||
return std::make_shared<ExtendedConnection>(handle, std::move(properties));
|
||||
return provider::ResourceHandle<data::stream::IOStream>(
|
||||
std::make_shared<ExtendedConnection>(handle, std::move(properties)),
|
||||
m_invalidator
|
||||
);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::get() {
|
||||
provider::ResourceHandle<oatpp::data::stream::IOStream> ConnectionProvider::get() {
|
||||
|
||||
fd_set set;
|
||||
struct timeval timeout;
|
||||
@ -399,29 +435,4 @@ std::shared_ptr<oatpp::data::stream::IOStream> ConnectionProvider::get() {
|
||||
|
||||
}
|
||||
|
||||
void ConnectionProvider::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
|
||||
/************************************************
|
||||
* WARNING!!!
|
||||
*
|
||||
* shutdown(handle, SHUT_RDWR) <--- DO!
|
||||
* close(handle); <--- DO NOT!
|
||||
*
|
||||
* DO NOT CLOSE file handle here -
|
||||
* USE shutdown instead.
|
||||
* Using close prevent FDs popping out of epoll,
|
||||
* and they'll be stuck there forever.
|
||||
************************************************/
|
||||
|
||||
auto c = std::static_pointer_cast<network::tcp::Connection>(connection);
|
||||
v_io_handle handle = c->getHandle();
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
shutdown(handle, SD_BOTH);
|
||||
#else
|
||||
shutdown(handle, SHUT_RDWR);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
@ -36,7 +36,16 @@ namespace oatpp { namespace network { namespace tcp { namespace server {
|
||||
/**
|
||||
* Simple provider of TCP connections.
|
||||
*/
|
||||
class ConnectionProvider : public base::Countable, public ServerConnectionProvider {
|
||||
class ConnectionProvider : public ServerConnectionProvider {
|
||||
private:
|
||||
|
||||
class ConnectionInvalidator : public provider::Invalidator<data::stream::IOStream> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -75,6 +84,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
network::Address m_address;
|
||||
std::atomic<bool> m_closed;
|
||||
oatpp::v_io_handle m_serverHandle;
|
||||
@ -83,8 +93,8 @@ private:
|
||||
oatpp::v_io_handle instantiateServer();
|
||||
private:
|
||||
bool prepareConnectionHandle(oatpp::v_io_handle handle);
|
||||
std::shared_ptr<data::stream::IOStream> getDefaultConnection();
|
||||
std::shared_ptr<data::stream::IOStream> getExtendedConnection();
|
||||
provider::ResourceHandle<data::stream::IOStream> getDefaultConnection();
|
||||
provider::ResourceHandle<data::stream::IOStream> getExtendedConnection();
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -122,7 +132,7 @@ public:
|
||||
* Get incoming connection.
|
||||
* @return &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
std::shared_ptr<data::stream::IOStream> get() override;
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
/**
|
||||
* No need to implement this.<br>
|
||||
@ -132,7 +142,7 @@ public:
|
||||
* <br>
|
||||
* *It may be implemented later*
|
||||
*/
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<data::stream::IOStream>&> getAsync() override {
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override {
|
||||
/*
|
||||
* No need to implement this.
|
||||
* For Asynchronous IO in oatpp it is considered to be a good practice
|
||||
@ -144,13 +154,6 @@ public:
|
||||
throw std::runtime_error("[oatpp::network::tcp::server::ConnectionProvider::getAsync()]: Error. Not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Call shutdown read and write on an underlying file descriptor.
|
||||
* `connection` **MUST** be an object previously obtained from **THIS** connection provider.
|
||||
* @param connection
|
||||
*/
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
/**
|
||||
* Get address - &id:oatpp::network::Address;.
|
||||
* @return
|
||||
|
@ -52,7 +52,7 @@ void Interface::registerInterface(const std::shared_ptr<Interface>& interface) {
|
||||
auto it = m_registry.find(interface->getName());
|
||||
if(it != m_registry.end()) {
|
||||
throw std::runtime_error
|
||||
("[oatpp::network::virtual_::Interface::registerInterface()]: Error. Interface with such name already exists - '" + interface->getName()->std_str() + "'.");
|
||||
("[oatpp::network::virtual_::Interface::registerInterface()]: Error. Interface with such name already exists - '" + *interface->getName() + "'.");
|
||||
}
|
||||
|
||||
m_registry.insert({interface->getName(), interface});
|
||||
@ -66,7 +66,7 @@ void Interface::unregisterInterface(const oatpp::String& name) {
|
||||
auto it = m_registry.find(name);
|
||||
if(it == m_registry.end()) {
|
||||
throw std::runtime_error
|
||||
("[oatpp::network::virtual_::Interface::unregisterInterface()]: Error. Interface NOT FOUND - '" + name->std_str() + "'.");
|
||||
("[oatpp::network::virtual_::Interface::unregisterInterface()]: Error. Interface NOT FOUND - '" + *name + "'.");
|
||||
}
|
||||
|
||||
m_registry.erase(it);
|
||||
@ -166,7 +166,7 @@ std::shared_ptr<Interface::ListenerLock> Interface::bind() {
|
||||
return std::shared_ptr<ListenerLock>(m_listenerLock.load());
|
||||
}
|
||||
throw std::runtime_error(
|
||||
"[oatpp::network::virtual_::Interface::bind()]: Can't bind to interface '" + m_name->std_str() + "'. Listener lock is already acquired");
|
||||
"[oatpp::network::virtual_::Interface::bind()]: Can't bind to interface '" + *m_name + "'. Listener lock is already acquired");
|
||||
}
|
||||
|
||||
void Interface::unbindListener(ListenerLock* listenerLock) {
|
||||
@ -184,7 +184,7 @@ std::shared_ptr<Interface::ConnectionSubmission> Interface::connect() {
|
||||
auto submission = std::make_shared<ConnectionSubmission>(true);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_submissions.pushBack(submission);
|
||||
m_submissions.push_back(submission);
|
||||
}
|
||||
m_condition.notify_one();
|
||||
return submission;
|
||||
@ -199,7 +199,7 @@ std::shared_ptr<Interface::ConnectionSubmission> Interface::connectNonBlocking()
|
||||
std::unique_lock<std::mutex> lock(m_mutex, std::try_to_lock);
|
||||
if (lock.owns_lock()) {
|
||||
submission = std::make_shared<ConnectionSubmission>(true);
|
||||
m_submissions.pushBack(submission);
|
||||
m_submissions.push_back(submission);
|
||||
}
|
||||
}
|
||||
if (submission) {
|
||||
@ -210,21 +210,28 @@ std::shared_ptr<Interface::ConnectionSubmission> Interface::connectNonBlocking()
|
||||
return std::make_shared<ConnectionSubmission>(false);
|
||||
}
|
||||
|
||||
std::shared_ptr<Socket> Interface::accept(const bool& waitingHandle) {
|
||||
std::shared_ptr<Socket> Interface::accept(const bool& waitingHandle,
|
||||
const std::chrono::duration<v_int64, std::micro>& timeout) {
|
||||
|
||||
auto startTime = std::chrono::system_clock::now();
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (waitingHandle && m_submissions.getFirstNode() == nullptr) {
|
||||
m_condition.wait(lock);
|
||||
while (waitingHandle && m_submissions.empty() && std::chrono::system_clock::now() - startTime < timeout) {
|
||||
m_condition.wait_for(lock, std::chrono::milliseconds (100));
|
||||
}
|
||||
if(!waitingHandle) {
|
||||
if(!waitingHandle || m_submissions.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return acceptSubmission(m_submissions.popFront());
|
||||
const auto submission = m_submissions.front();
|
||||
m_submissions.pop_front();
|
||||
return acceptSubmission(submission);
|
||||
}
|
||||
|
||||
std::shared_ptr<Socket> Interface::acceptNonBlocking() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex, std::try_to_lock);
|
||||
if(lock.owns_lock() && m_submissions.getFirstNode() != nullptr) {
|
||||
return acceptSubmission(m_submissions.popFront());
|
||||
if(lock.owns_lock() && !m_submissions.empty()) {
|
||||
const auto submission = m_submissions.front();
|
||||
m_submissions.pop_front();
|
||||
return acceptSubmission(submission);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -233,14 +240,9 @@ void Interface::dropAllConnection() {
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto curr = m_submissions.getFirstNode();
|
||||
|
||||
while(curr != nullptr) {
|
||||
auto submission = curr->getData();
|
||||
for (const auto& submission : m_submissions) {
|
||||
submission->invalidate();
|
||||
curr = curr->getNext();
|
||||
}
|
||||
|
||||
m_submissions.clear();
|
||||
|
||||
}
|
||||
|
@ -27,9 +27,9 @@
|
||||
|
||||
#include "./Socket.hpp"
|
||||
|
||||
#include "oatpp/core/collection/LinkedList.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
|
||||
namespace oatpp { namespace network { namespace virtual_ {
|
||||
|
||||
@ -116,7 +116,7 @@ private:
|
||||
std::mutex m_listenerMutex;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
oatpp::collection::LinkedList<std::shared_ptr<ConnectionSubmission>> m_submissions;
|
||||
std::list<std::shared_ptr<ConnectionSubmission>> m_submissions;
|
||||
private:
|
||||
|
||||
Interface(const oatpp::String& name);
|
||||
@ -162,9 +162,11 @@ public:
|
||||
* Block and wait for incloming connection.
|
||||
* @param waitingHandle - reference to a boolean variable.
|
||||
* User may set waitingHandle = false and call &l:Interface::notifyAcceptors (); in order to break waiting loop. and exit accept() method.
|
||||
* @param timeout
|
||||
* @return - `std::shared_ptr` to &id:oatpp::network::virtual_::Socket;.
|
||||
*/
|
||||
std::shared_ptr<Socket> accept(const bool& waitingHandle = true);
|
||||
std::shared_ptr<Socket> accept(const bool& waitingHandle = true,
|
||||
const std::chrono::duration<v_int64, std::micro>& timeout = std::chrono::minutes (10));
|
||||
|
||||
/**
|
||||
* Check if incoming connection is available. NonBlocking.
|
||||
|
@ -124,11 +124,13 @@ v_io_size Pipe::Writer::write(const void *data, v_buff_size count, async::Action
|
||||
|
||||
std::lock_guard<std::mutex> lock(pipe.m_mutex);
|
||||
|
||||
if (pipe.m_fifo.availableToWrite() > 0) {
|
||||
result = pipe.m_fifo.write(data, count);
|
||||
} else if (pipe.m_open) {
|
||||
action = async::Action::createWaitListAction(&m_waitList);
|
||||
result = IOError::RETRY_WRITE;
|
||||
if(pipe.m_open) {
|
||||
if (pipe.m_fifo.availableToWrite() > 0) {
|
||||
result = pipe.m_fifo.write(data, count);
|
||||
} else {
|
||||
action = async::Action::createWaitListAction(&m_waitList);
|
||||
result = IOError::RETRY_WRITE;
|
||||
}
|
||||
} else {
|
||||
result = IOError::BROKEN_PIPE;
|
||||
}
|
||||
|
@ -80,8 +80,6 @@ oatpp::data::stream::Context& Socket::getInputStreamContext() {
|
||||
void Socket::close() {
|
||||
m_pipeIn->close();
|
||||
m_pipeOut->close();
|
||||
m_pipeIn.reset();
|
||||
m_pipeOut.reset();
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -26,8 +26,14 @@
|
||||
|
||||
namespace oatpp { namespace network { namespace virtual_ { namespace client {
|
||||
|
||||
void ConnectionProvider::ConnectionInvalidator::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
auto socket = std::static_pointer_cast<Socket>(connection);
|
||||
socket->close();
|
||||
}
|
||||
|
||||
ConnectionProvider::ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface)
|
||||
: m_interface(interface)
|
||||
: m_invalidator(std::make_shared<ConnectionInvalidator>())
|
||||
, m_interface(interface)
|
||||
, m_maxAvailableToRead(-1)
|
||||
, m_maxAvailableToWrite(-1)
|
||||
{
|
||||
@ -43,7 +49,7 @@ void ConnectionProvider::stop() {
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<data::stream::IOStream> ConnectionProvider::get() {
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProvider::get() {
|
||||
auto submission = m_interface->connect();
|
||||
if(submission->isValid()) {
|
||||
auto socket = submission->getSocket();
|
||||
@ -51,26 +57,30 @@ std::shared_ptr<data::stream::IOStream> ConnectionProvider::get() {
|
||||
socket->setOutputStreamIOMode(oatpp::data::stream::IOMode::BLOCKING);
|
||||
socket->setInputStreamIOMode(oatpp::data::stream::IOMode::BLOCKING);
|
||||
socket->setMaxAvailableToReadWrtie(m_maxAvailableToRead, m_maxAvailableToWrite);
|
||||
return socket;
|
||||
return provider::ResourceHandle<data::stream::IOStream>(socket, m_invalidator);
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("[oatpp::network::virtual_::client::getConnection()]: Error. Can't connect. " + m_interface->getName()->std_str());
|
||||
throw std::runtime_error("[oatpp::network::virtual_::client::getConnection()]: Error. Can't connect. " + *m_interface->getName());
|
||||
}
|
||||
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::stream::IOStream>&> ConnectionProvider::getAsync() {
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&>
|
||||
ConnectionProvider::getAsync() {
|
||||
|
||||
class ConnectCoroutine : public oatpp::async::CoroutineWithResult<ConnectCoroutine, const std::shared_ptr<oatpp::data::stream::IOStream>&> {
|
||||
class ConnectCoroutine : public oatpp::async::CoroutineWithResult<ConnectCoroutine, const provider::ResourceHandle<oatpp::data::stream::IOStream>&> {
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
std::shared_ptr<virtual_::Interface> m_interface;
|
||||
v_io_size m_maxAvailableToRead;
|
||||
v_io_size m_maxAvailableToWrite;
|
||||
std::shared_ptr<virtual_::Interface::ConnectionSubmission> m_submission;
|
||||
public:
|
||||
|
||||
ConnectCoroutine(const std::shared_ptr<virtual_::Interface>& interface,
|
||||
ConnectCoroutine(const std::shared_ptr<ConnectionInvalidator>& invalidator,
|
||||
const std::shared_ptr<virtual_::Interface>& interface,
|
||||
v_io_size maxAvailableToRead,
|
||||
v_io_size maxAvailableToWrite)
|
||||
: m_interface(interface)
|
||||
: m_invalidator(invalidator)
|
||||
, m_interface(interface)
|
||||
, m_maxAvailableToRead(maxAvailableToRead)
|
||||
, m_maxAvailableToWrite(maxAvailableToWrite)
|
||||
{}
|
||||
@ -93,7 +103,7 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
socket->setOutputStreamIOMode(oatpp::data::stream::IOMode::ASYNCHRONOUS);
|
||||
socket->setInputStreamIOMode(oatpp::data::stream::IOMode::ASYNCHRONOUS);
|
||||
socket->setMaxAvailableToReadWrtie(m_maxAvailableToRead, m_maxAvailableToWrite);
|
||||
return _return(socket);
|
||||
return _return(provider::ResourceHandle<data::stream::IOStream>(socket, m_invalidator));
|
||||
}
|
||||
|
||||
return waitRepeat(std::chrono::milliseconds(100));
|
||||
@ -105,7 +115,7 @@ oatpp::async::CoroutineStarterForResult<const std::shared_ptr<oatpp::data::strea
|
||||
|
||||
};
|
||||
|
||||
return ConnectCoroutine::startForResult(m_interface, m_maxAvailableToRead, m_maxAvailableToWrite);
|
||||
return ConnectCoroutine::startForResult(m_invalidator, m_interface, m_maxAvailableToRead, m_maxAvailableToWrite);
|
||||
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,17 @@ namespace oatpp { namespace network { namespace virtual_ { namespace client {
|
||||
* Extends &id:oatpp::network::ClientConnectionProvider;.
|
||||
*/
|
||||
class ConnectionProvider : public oatpp::network::ClientConnectionProvider {
|
||||
private:
|
||||
|
||||
class ConnectionInvalidator : public provider::Invalidator<data::stream::IOStream> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
private:
|
||||
std::shared_ptr<virtual_::Interface> m_interface;
|
||||
v_io_size m_maxAvailableToRead;
|
||||
@ -75,22 +86,13 @@ public:
|
||||
* Get connection.
|
||||
* @return - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
std::shared_ptr<data::stream::IOStream> get() override;
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
/**
|
||||
* Get connection in asynchronous manner.
|
||||
* @return - &id:oatpp::async::CoroutineStarterForResult;.
|
||||
*/
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
* @param connection
|
||||
*/
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override {
|
||||
(void)connection;
|
||||
// DO Nothing.
|
||||
}
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -24,10 +24,18 @@
|
||||
|
||||
#include "ConnectionProvider.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace oatpp { namespace network { namespace virtual_ { namespace server {
|
||||
|
||||
void ConnectionProvider::ConnectionInvalidator::invalidate(const std::shared_ptr<data::stream::IOStream>& connection) {
|
||||
auto socket = std::static_pointer_cast<Socket>(connection);
|
||||
socket->close();
|
||||
}
|
||||
|
||||
ConnectionProvider::ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface)
|
||||
: m_interface(interface)
|
||||
: m_invalidator(std::make_shared<ConnectionInvalidator>())
|
||||
, m_interface(interface)
|
||||
, m_listenerLock(interface->bind())
|
||||
, m_open(true)
|
||||
, m_maxAvailableToRead(-1)
|
||||
@ -52,12 +60,12 @@ void ConnectionProvider::stop() {
|
||||
m_interface->notifyAcceptors();
|
||||
}
|
||||
|
||||
std::shared_ptr<data::stream::IOStream> ConnectionProvider::get() {
|
||||
auto socket = m_interface->accept(m_open);
|
||||
provider::ResourceHandle<data::stream::IOStream> ConnectionProvider::get() {
|
||||
auto socket = m_interface->accept(m_open, std::chrono::milliseconds(500));
|
||||
if(socket) {
|
||||
socket->setMaxAvailableToReadWrtie(m_maxAvailableToRead, m_maxAvailableToWrite);
|
||||
}
|
||||
return socket;
|
||||
return provider::ResourceHandle<data::stream::IOStream>(socket, m_invalidator);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
@ -37,6 +37,16 @@ namespace oatpp { namespace network { namespace virtual_ { namespace server {
|
||||
*/
|
||||
class ConnectionProvider : public oatpp::network::ServerConnectionProvider {
|
||||
private:
|
||||
|
||||
class ConnectionInvalidator : public provider::Invalidator<data::stream::IOStream> {
|
||||
public:
|
||||
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConnectionInvalidator> m_invalidator;
|
||||
std::shared_ptr<virtual_::Interface> m_interface;
|
||||
std::shared_ptr<virtual_::Interface::ListenerLock> m_listenerLock;
|
||||
bool m_open;
|
||||
@ -74,7 +84,7 @@ public:
|
||||
* Get incoming connection.
|
||||
* @return &id:oatpp::data::stream::IOStream;.
|
||||
*/
|
||||
std::shared_ptr<data::stream::IOStream> get() override;
|
||||
provider::ResourceHandle<data::stream::IOStream> get() override;
|
||||
|
||||
/**
|
||||
* **NOT IMPLEMENTED!**<br>
|
||||
@ -85,7 +95,7 @@ public:
|
||||
* <br>
|
||||
* *It may be implemented later.*
|
||||
*/
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<data::stream::IOStream>&> getAsync() override {
|
||||
oatpp::async::CoroutineStarterForResult<const provider::ResourceHandle<data::stream::IOStream>&> getAsync() override {
|
||||
/*
|
||||
* No need to implement this.
|
||||
* For Asynchronous IO in oatpp it is considered to be a good practice
|
||||
@ -96,15 +106,6 @@ public:
|
||||
*/
|
||||
throw std::runtime_error("[oatpp::network::virtual_::server::ConnectionProvider::getConnectionAsync()]: Error. Not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
* @param connection
|
||||
*/
|
||||
void invalidate(const std::shared_ptr<data::stream::IOStream>& connection) override {
|
||||
(void)connection;
|
||||
// DO Nothing.
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ void SchemaMigration::migrate() {
|
||||
break;
|
||||
|
||||
case SOURCE_FILE:
|
||||
script = base::StrBuffer::loadFromFile(source.param->c_str());
|
||||
script = oatpp::String::loadFromFile(source.param->c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -36,7 +36,7 @@ Transaction::Transaction(const base::ObjectHandle<Executor>& executor, const std
|
||||
} else {
|
||||
m_open = false;
|
||||
throw std::runtime_error("[oatpp::orm::Transaction::Transaction()]: "
|
||||
"Error. Can't begin transaction - " + res->getErrorMessage()->std_str());
|
||||
"Error. Can't begin transaction - " + *res->getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,9 @@ Beautifier::Beautifier(ConsistentOutputStream* outputStream, const oatpp::String
|
||||
{}
|
||||
|
||||
void Beautifier::writeIndent(ConsistentOutputStream* outputStream) {
|
||||
outputStream->writeSimple(m_newLine->getData(), m_newLine->getSize());
|
||||
outputStream->writeSimple(m_newLine->data(), m_newLine->size());
|
||||
for(v_int32 i = 0; i < m_level; i ++ ) {
|
||||
outputStream->writeSimple(m_indent->getData(), m_indent->getSize());
|
||||
outputStream->writeSimple(m_indent->data(), m_indent->size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
namespace oatpp { namespace parser { namespace json{
|
||||
|
||||
v_buff_size Utils::calcEscapedStringSize(p_char8 data, v_buff_size size, v_buff_size& safeSize) {
|
||||
v_buff_size Utils::calcEscapedStringSize(const char* data, v_buff_size size, v_buff_size& safeSize, v_uint32 flags) {
|
||||
v_buff_size result = 0;
|
||||
v_buff_size i = 0;
|
||||
safeSize = size;
|
||||
@ -37,18 +37,39 @@ v_buff_size Utils::calcEscapedStringSize(p_char8 data, v_buff_size size, v_buff_
|
||||
v_char8 a = data[i];
|
||||
if(a < 32) {
|
||||
i ++;
|
||||
if(a == '\b' || a == '\f' || a == '\n' || a == '\r' || a == '\t'){
|
||||
result += 2; // '\n'
|
||||
} else {
|
||||
result += 6; // '\uFFFF' - 6 chars
|
||||
|
||||
switch (a) {
|
||||
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t': result += 2; break; // '\n'
|
||||
|
||||
default:
|
||||
result += 6; // '\uFFFF' - 6 chars
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else if(a < 128){
|
||||
i ++;
|
||||
if(a == '\"' || a == '\\' || a == '/'){
|
||||
result += 2; // '\/'
|
||||
} else {
|
||||
result ++;
|
||||
|
||||
switch (a) {
|
||||
case '\"':
|
||||
case '\\': result += 2; break; // '\/'
|
||||
|
||||
case '/':
|
||||
result ++;
|
||||
if((flags & FLAG_ESCAPE_SOLIDUS) > 0) result ++;
|
||||
break;
|
||||
|
||||
default:
|
||||
result ++;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
v_buff_size charSize = oatpp::encoding::Unicode::getUtf8CharSequenceLength(a);
|
||||
if(charSize != 0) {
|
||||
@ -73,7 +94,7 @@ v_buff_size Utils::calcEscapedStringSize(p_char8 data, v_buff_size size, v_buff_
|
||||
return result;
|
||||
}
|
||||
|
||||
v_buff_size Utils::calcUnescapedStringSize(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition) {
|
||||
v_buff_size Utils::calcUnescapedStringSize(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition) {
|
||||
errorCode = 0;
|
||||
v_buff_size result = 0;
|
||||
v_buff_size i = 0;
|
||||
@ -168,7 +189,7 @@ v_buff_size Utils::calcUnescapedStringSize(p_char8 data, v_buff_size size, v_int
|
||||
return result;
|
||||
}
|
||||
|
||||
v_buff_size Utils::escapeUtf8Char(p_char8 sequence, p_char8 buffer){
|
||||
v_buff_size Utils::escapeUtf8Char(const char* sequence, p_char8 buffer){
|
||||
v_buff_size length;
|
||||
v_int32 code = oatpp::encoding::Unicode::encodeUtf8Char(sequence, length);
|
||||
if(code < 0x00010000) {
|
||||
@ -195,15 +216,15 @@ v_buff_size Utils::escapeUtf8Char(p_char8 sequence, p_char8 buffer){
|
||||
return 11;
|
||||
}
|
||||
}
|
||||
|
||||
oatpp::String Utils::escapeString(p_char8 data, v_buff_size size, bool copyAsOwnData) {
|
||||
|
||||
oatpp::String Utils::escapeString(const char* data, v_buff_size size, v_uint32 flags) {
|
||||
v_buff_size safeSize;
|
||||
v_buff_size escapedSize = calcEscapedStringSize(data, size, safeSize);
|
||||
v_buff_size escapedSize = calcEscapedStringSize(data, size, safeSize, flags);
|
||||
if(escapedSize == size) {
|
||||
return String((const char*)data, size, copyAsOwnData);
|
||||
return String((const char*)data, size);
|
||||
}
|
||||
auto result = String(escapedSize);
|
||||
p_char8 resultData = result->getData();
|
||||
p_char8 resultData = (p_char8) result->data();
|
||||
v_buff_size pos = 0;
|
||||
|
||||
{
|
||||
@ -211,43 +232,51 @@ oatpp::String Utils::escapeString(p_char8 data, v_buff_size size, bool copyAsOwn
|
||||
while (i < safeSize) {
|
||||
v_char8 a = data[i];
|
||||
if (a < 32) {
|
||||
if (a == '\b') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = 'b'; pos += 2;
|
||||
}
|
||||
else if (a == '\f') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = 'f'; pos += 2;
|
||||
}
|
||||
else if (a == '\n') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = 'n'; pos += 2;
|
||||
}
|
||||
else if (a == '\r') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = 'r'; pos += 2;
|
||||
}
|
||||
else if (a == '\t') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = 't'; pos += 2;
|
||||
}
|
||||
else {
|
||||
resultData[pos] = '\\';
|
||||
resultData[pos + 1] = 'u';
|
||||
oatpp::encoding::Hex::writeUInt16(a, &resultData[pos + 2]);
|
||||
pos += 6;
|
||||
|
||||
switch (a) {
|
||||
|
||||
case '\b': resultData[pos] = '\\'; resultData[pos + 1] = 'b'; pos += 2; break;
|
||||
case '\f': resultData[pos] = '\\'; resultData[pos + 1] = 'f'; pos += 2; break;
|
||||
case '\n': resultData[pos] = '\\'; resultData[pos + 1] = 'n'; pos += 2; break;
|
||||
case '\r': resultData[pos] = '\\'; resultData[pos + 1] = 'r'; pos += 2; break;
|
||||
case '\t': resultData[pos] = '\\'; resultData[pos + 1] = 't'; pos += 2; break;
|
||||
|
||||
default:
|
||||
resultData[pos] = '\\';
|
||||
resultData[pos + 1] = 'u';
|
||||
oatpp::encoding::Hex::writeUInt16(a, &resultData[pos + 2]);
|
||||
pos += 6;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
}
|
||||
else if (a < 128) {
|
||||
if (a == '\"') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = '"'; pos += 2;
|
||||
}
|
||||
else if (a == '\\') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = '\\'; pos += 2;
|
||||
}
|
||||
else if (a == '/') {
|
||||
resultData[pos] = '\\'; resultData[pos + 1] = '/'; pos += 2;
|
||||
}
|
||||
else {
|
||||
resultData[pos] = data[i];
|
||||
pos++;
|
||||
|
||||
switch (a) {
|
||||
case '\"': resultData[pos] = '\\'; resultData[pos + 1] = '"'; pos += 2; break;
|
||||
case '\\': resultData[pos] = '\\'; resultData[pos + 1] = '\\'; pos += 2; break;
|
||||
|
||||
case '/':
|
||||
if((flags & FLAG_ESCAPE_SOLIDUS) > 0) {
|
||||
resultData[pos] = '\\';
|
||||
resultData[pos + 1] = '/';
|
||||
pos += 2;
|
||||
} else {
|
||||
resultData[pos] = data[i];
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
resultData[pos] = data[i];
|
||||
pos++;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
@ -267,7 +296,7 @@ oatpp::String Utils::escapeString(p_char8 data, v_buff_size size, bool copyAsOwn
|
||||
}
|
||||
|
||||
if(size > safeSize){
|
||||
for(v_buff_size i = pos; i < result->getSize(); i ++){
|
||||
for(v_buff_size i = pos; i < result->size(); i ++){
|
||||
resultData[i] = '?';
|
||||
}
|
||||
}
|
||||
@ -275,7 +304,7 @@ oatpp::String Utils::escapeString(p_char8 data, v_buff_size size, bool copyAsOwn
|
||||
return result;
|
||||
}
|
||||
|
||||
void Utils::unescapeStringToBuffer(p_char8 data, v_buff_size size, p_char8 resultData){
|
||||
void Utils::unescapeStringToBuffer(const char* data, v_buff_size size, p_char8 resultData){
|
||||
|
||||
v_buff_size i = 0;
|
||||
v_buff_size pos = 0;
|
||||
@ -331,7 +360,7 @@ void Utils::unescapeStringToBuffer(p_char8 data, v_buff_size size, p_char8 resul
|
||||
|
||||
}
|
||||
|
||||
oatpp::String Utils::unescapeString(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition) {
|
||||
oatpp::String Utils::unescapeString(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition) {
|
||||
|
||||
v_buff_size unescapedSize = calcUnescapedStringSize(data, size, errorCode, errorPosition);
|
||||
if(errorCode != 0){
|
||||
@ -339,15 +368,15 @@ oatpp::String Utils::unescapeString(p_char8 data, v_buff_size size, v_int64& err
|
||||
}
|
||||
auto result = String(unescapedSize);
|
||||
if(unescapedSize == size) {
|
||||
std::memcpy(result->getData(), data, size);
|
||||
std::memcpy((void*) result->data(), data, size);
|
||||
} else {
|
||||
unescapeStringToBuffer(data, size, result->getData());
|
||||
unescapeStringToBuffer(data, size, (p_char8) result->data());
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
std::string Utils::unescapeStringToStdString(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition){
|
||||
std::string Utils::unescapeStringToStdString(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition){
|
||||
|
||||
v_buff_size unescapedSize = calcUnescapedStringSize(data, size, errorCode, errorPosition);
|
||||
if(errorCode != 0){
|
||||
@ -364,11 +393,11 @@ std::string Utils::unescapeStringToStdString(p_char8 data, v_buff_size size, v_i
|
||||
|
||||
}
|
||||
|
||||
p_char8 Utils::preparseString(ParsingCaret& caret, v_buff_size& size){
|
||||
const char* Utils::preparseString(ParsingCaret& caret, v_buff_size& size){
|
||||
|
||||
if(caret.canContinueAtChar('"', 1)){
|
||||
|
||||
const p_char8 data = caret.getData();
|
||||
const char* data = caret.getData();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
v_buff_size pos0 = pos;
|
||||
v_buff_size length = caret.getDataSize();
|
||||
@ -397,7 +426,7 @@ p_char8 Utils::preparseString(ParsingCaret& caret, v_buff_size& size){
|
||||
oatpp::String Utils::parseString(ParsingCaret& caret) {
|
||||
|
||||
v_buff_size size;
|
||||
p_char8 data = preparseString(caret, size);
|
||||
const char* data = preparseString(caret, size);
|
||||
|
||||
if(data != nullptr) {
|
||||
|
||||
@ -424,7 +453,7 @@ oatpp::String Utils::parseString(ParsingCaret& caret) {
|
||||
std::string Utils::parseStringToStdString(ParsingCaret& caret){
|
||||
|
||||
v_buff_size size;
|
||||
p_char8 data = preparseString(caret, size);
|
||||
auto data = preparseString(caret, size);
|
||||
|
||||
if(data != nullptr) {
|
||||
|
||||
|
@ -37,6 +37,12 @@ namespace oatpp { namespace parser { namespace json {
|
||||
* Used by &id:oatpp::parser::json::mapping::Serializer;, &id:oatpp::parser::json::mapping::Deserializer;.
|
||||
*/
|
||||
class Utils {
|
||||
public:
|
||||
|
||||
static constexpr v_uint32 FLAG_ESCAPE_SOLIDUS = 1;
|
||||
|
||||
static constexpr v_uint32 FLAG_ESCAPE_ALL = FLAG_ESCAPE_SOLIDUS;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -59,11 +65,11 @@ public:
|
||||
typedef oatpp::String String;
|
||||
typedef oatpp::parser::Caret ParsingCaret;
|
||||
private:
|
||||
static v_buff_size escapeUtf8Char(p_char8 sequence, p_char8 buffer);
|
||||
static v_buff_size calcEscapedStringSize(p_char8 data, v_buff_size size, v_buff_size& safeSize);
|
||||
static v_buff_size calcUnescapedStringSize(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
static void unescapeStringToBuffer(p_char8 data, v_buff_size size, p_char8 resultData);
|
||||
static p_char8 preparseString(ParsingCaret& caret, v_buff_size& size);
|
||||
static v_buff_size escapeUtf8Char(const char* sequence, p_char8 buffer);
|
||||
static v_buff_size calcEscapedStringSize(const char* data, v_buff_size size, v_buff_size& safeSize, v_uint32 flags);
|
||||
static v_buff_size calcUnescapedStringSize(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
static void unescapeStringToBuffer(const char* data, v_buff_size size, p_char8 resultData);
|
||||
static const char* preparseString(ParsingCaret& caret, v_buff_size& size);
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -71,10 +77,10 @@ public:
|
||||
* *Note:* if(copyAsOwnData == false && escapedString == initialString) then result string will point to initial data.
|
||||
* @param data - pointer to string to escape.
|
||||
* @param size - data size.
|
||||
* @param copyAsOwnData - see &id:oatpp::base::StrBuffer::StrBuffer;.
|
||||
* @param flags - escape flags.
|
||||
* @return - &id:oatpp::String;.
|
||||
*/
|
||||
static String escapeString(p_char8 data, v_buff_size size, bool copyAsOwnData = true);
|
||||
static String escapeString(const char* data, v_buff_size size, v_uint32 flags = FLAG_ESCAPE_ALL);
|
||||
|
||||
/**
|
||||
* Unescape string as for json standard.
|
||||
@ -90,7 +96,7 @@ public:
|
||||
* @param errorPosition - out parameter. Error position in data.
|
||||
* @return - &id:oatpp::String;.
|
||||
*/
|
||||
static String unescapeString(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
static String unescapeString(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
|
||||
/**
|
||||
* Same as &l:Utils::unescapeString (); but return `std::string`.
|
||||
@ -106,7 +112,7 @@ public:
|
||||
* @param errorPosition - out parameter. Error position in data.
|
||||
* @return - &id:oatpp::String;.
|
||||
*/
|
||||
static std::string unescapeStringToStdString(p_char8 data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
static std::string unescapeStringToStdString(const char* data, v_buff_size size, v_int64& errorCode, v_buff_size& errorPosition);
|
||||
|
||||
/**
|
||||
* Parse string enclosed in `"<string>"`.
|
||||
|
@ -76,7 +76,7 @@ void Deserializer::setDeserializerMethod(const data::mapping::type::ClassId& cla
|
||||
|
||||
void Deserializer::skipScope(oatpp::parser::Caret& caret, v_char8 charOpen, v_char8 charClose){
|
||||
|
||||
p_char8 data = caret.getData();
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
v_int32 scopeCounter = 0;
|
||||
@ -109,7 +109,7 @@ void Deserializer::skipScope(oatpp::parser::Caret& caret, v_char8 charOpen, v_ch
|
||||
}
|
||||
|
||||
void Deserializer::skipString(oatpp::parser::Caret& caret){
|
||||
p_char8 data = caret.getData();
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
v_int32 scopeCounter = 0;
|
||||
@ -129,7 +129,7 @@ void Deserializer::skipString(oatpp::parser::Caret& caret){
|
||||
}
|
||||
|
||||
void Deserializer::skipToken(oatpp::parser::Caret& caret){
|
||||
p_char8 data = caret.getData();
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
while(pos < size){
|
||||
@ -252,7 +252,7 @@ oatpp::Void Deserializer::deserializeAny(Deserializer* deserializer, parser::Car
|
||||
const Type* const fieldType = guessType(caret);
|
||||
if(fieldType != nullptr) {
|
||||
auto fieldValue = deserializer->deserialize(caret, fieldType);
|
||||
auto anyHandle = std::make_shared<data::mapping::type::AnyHandle>(fieldValue.getPtr(), fieldValue.valueType);
|
||||
auto anyHandle = std::make_shared<data::mapping::type::AnyHandle>(fieldValue.getPtr(), fieldValue.getValueType());
|
||||
return oatpp::Void(anyHandle, Any::Class::getType());
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ private:
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
return oatpp::Void(list.getPtr(), list.valueType);
|
||||
return oatpp::Void(list.getPtr(), list.getValueType());
|
||||
} else {
|
||||
caret.setError("[oatpp::parser::json::mapping::Deserializer::deserializeList()]: Error. '[' - expected", ERROR_CODE_ARRAY_SCOPE_OPEN);
|
||||
return nullptr;
|
||||
@ -266,7 +266,7 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return oatpp::Void(map.getPtr(), map.valueType);
|
||||
return oatpp::Void(map.getPtr(), map.getValueType());
|
||||
|
||||
} else {
|
||||
caret.setError("[oatpp::parser::json::mapping::Deserializer::deserializeKeyValue()]: Error. '{' - expected", ERROR_CODE_OBJECT_SCOPE_OPEN);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user