Merge pull request #1 from oatpp/master

upgrade
This commit is contained in:
NickPak 2021-10-28 16:54:18 +08:00 committed by GitHub
commit 39c86ebbd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
254 changed files with 8325 additions and 3629 deletions

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
# These are supported funding model platforms
github: oatpp

View File

@ -21,6 +21,7 @@ option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(OATPP_INSTALL "Create installation target for oat++" ON)
option(OATPP_BUILD_TESTS "Create test target for oat++" ON)
option(OATPP_LINK_ATOMIC "Link atomic library for other platform than MSVC|MINGW|APPLE|FreeBSD" ON)
option(OATPP_MSVC_LINK_STATIC_RUNTIME "MSVC: Link with static runtime (/MT and /MTd)." OFF)
###################################################################################################
## COMPILATION CONFIG #############################################################################
@ -113,6 +114,9 @@ message("oatpp version: '${OATPP_THIS_MODULE_VERSION}'")
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
include(cmake/msvc-runtime.cmake)
configure_msvc_runtime()
add_subdirectory(src)
if(OATPP_BUILD_TESTS)

255
README.md
View File

@ -17,10 +17,11 @@
# Oat++
**Attention**
**News**
- Version `1.2.0` is now merged to Master and soon will receive a release tag. Get ready to migrate - see the [changelog](changelog/1.2.0.md) for details.
- To checkout the latest `1.1.0` code use this commit - [e577681355ca652f317867c609e07cefabc37c0a](https://github.com/oatpp/oatpp/tree/e577681355ca652f317867c609e07cefabc37c0a)
- Hey, the new oatpp version `1.3.0` is now in the master branch :tada: and soon will receive its release tag.
Follow [changelog](https://github.com/oatpp/oatpp/blob/master/changelog/1.3.0.md) for details, and prepare for migration.
See [project build status](https://oatpp.io/status/build/) for update progress.
---
@ -30,245 +31,141 @@ It's fully loaded and contains all necessary components for effective production
It's also light and has a small memory footprint.
**Start**
- [Get Started](https://oatpp.io/docs/start/)
- [Build For Unix/Linux](https://oatpp.io/docs/installation/unix-linux/)
- [Build For Windows](https://oatpp.io/docs/installation/windows/)
- [Examples](#examples)
**About**
- [Website](https://oatpp.io/)
- [Supported Platforms](https://oatpp.io/supported-platforms/)
- Latest Benchmarks: [5 Million WebSockets](https://oatpp.io/benchmark/websocket/5-million/)
- [Contributing to Oat++](CONTRIBUTING.md)
**Join Our Community**
- Chat on **Gitter**. [Oat++ framework/Lobby](https://gitter.im/oatpp-framework/Lobby)
- Follow us on **Twitter** for latest news. [@oatpp_io](https://twitter.com/oatpp_io)
- Join community on **Reddit**. [r/oatpp](https://www.reddit.com/r/oatpp/)
## High Level Overview
- [Gitter](https://gitter.im/oatpp-framework/Lobby) - Talk to Oat++ developers and to other Oat++ users.
- [Twitter](https://twitter.com/oatpp_io) - Follow Oat++ on Twitter.
- [Reddit](https://www.reddit.com/r/oatpp/) - Follow Oat++ subreddit.
- [StackOverflow (new)](https://stackoverflow.com/questions/tagged/oat%2b%2b) - Post a Question.
- [API Controller And Request Mapping](#api-controller-and-request-mapping)
* [Declare Endpoint](#declare-endpoint)
* [Add CORS for Endpoint](#add-cors-for-endpoint)
* [Endpoint with Authorization](#endpoint-with-authorization)
- [Swagger-UI Annotations](#swagger-ui-annotations)
* [Additional Endpoint Info](#additional-endpoint-info)
- [API Client - Retrofit / Feign Like Client](#api-client---retrofit--feign-like-client)
* [Declare Client](#declare-client)
* [Using API Client](#using-api-client)
- [Object Mapping](#object-mapping)
* [Declare DTO](#declare-dto)
* [Serialize DTO Using ObjectMapper](#serialize-dto-using-objectmapper)
## Quick Overview
**Shortcuts:**
### API Controller And Request Mapping
- [Oat++ High Level Overview](https://oatpp.io/docs/start/high-level-overview/) - Get a quick overview of Oat++ features.
- [Example Project](https://github.com/oatpp/example-crud) - A complete example of a "CRUD" service (UserService) built with Oat++. REST + Swagger-UI + SQLite.
For more info see [Api Controller](https://oatpp.io/docs/components/api-controller/)
### Build Powerful API And Document It With Swagger-UI
#### Declare Endpoint
See [ApiController](https://oatpp.io/docs/components/api-controller/) for more details.
```cpp
ENDPOINT("PUT", "/users/{userId}", putUser,
PATH(Int64, userId),
BODY_DTO(Object<UserDto>, userDto))
{
userDto->id = userId;
return createDtoResponse(Status::CODE_200, m_database->updateUser(userDto));
}
```
ENDPOINT_INFO(getUserById) {
info->summary = "Get one User by userId";
#### Add CORS for Endpoint
For more info see [Api Controller / CORS](https://oatpp.io/docs/components/api-controller/#cors)
```cpp
ADD_CORS(putUser)
ENDPOINT("PUT", "/users/{userId}", putUser,
PATH(Int64, userId),
BODY_DTO(Object<UserDto>, userDto))
{
userDto->id = userId;
return createDtoResponse(Status::CODE_200, m_database->updateUser(userDto));
}
```
#### Endpoint with Authorization
For more info see [Api Controller / Authorization](https://oatpp.io/docs/components/api-controller/#authorization-basic)
```cpp
using namespace oatpp::web::server::handler;
ENDPOINT("PUT", "/users/{userId}", putUser,
AUTHORIZATION(std::shared_ptr<DefaultBasicAuthorizationObject>, authObject),
PATH(Int64, userId),
BODY_DTO(Object<UserDto>, userDto))
{
OATPP_ASSERT_HTTP(authObject->userId == "Ivan" && authObject->password == "admin", Status::CODE_401, "Unauthorized");
userDto->id = userId;
return createDtoResponse(Status::CODE_200, m_database->updateUser(userDto));
}
```
### Swagger-UI Annotations
For more info see [Endpoint Annotation And API Documentation](https://oatpp.io/docs/components/api-controller/#endpoint-annotation-and-api-documentation)
#### Additional Endpoint Info
```cpp
ENDPOINT_INFO(putUser) {
// general
info->summary = "Update User by userId";
info->addConsumes<Object<UserDto>>("application/json");
info->addResponse<Object<UserDto>>(Status::CODE_200, "application/json");
info->addResponse<String>(Status::CODE_404, "text/plain");
// params specific
info->addResponse<Object<StatusDto>>(Status::CODE_404, "application/json");
info->addResponse<Object<StatusDto>>(Status::CODE_500, "application/json");
info->pathParams["userId"].description = "User Identifier";
}
ENDPOINT("PUT", "/users/{userId}", putUser,
PATH(Int64, userId),
BODY_DTO(Object<UserDto>, userDto))
ENDPOINT("GET", "users/{userId}", getUserById,
PATH(Int32, userId))
{
userDto->id = userId;
return createDtoResponse(Status::CODE_200, m_database->updateUser(userDto));
return createDtoResponse(Status::CODE_200, m_userService.getUserById(userId));
}
```
```
### API Client - Retrofit / Feign Like Client
### Access Databases And Keep Your Data Consistent
For more info see [Api Client](https://oatpp.io/docs/components/api-client/)
#### Declare Client
See [Oat++ ORM](https://oatpp.io/docs/components/orm/) for more details.
```cpp
class UserService : public oatpp::web::client::ApiClient {
public:
API_CLIENT_INIT(UserService)
API_CALL("GET", "/users", getUsers)
API_CALL("GET", "/users/{userId}", getUserById, PATH(Int64, userId))
};
QUERY(createUser,
"INSERT INTO users (username, email, role) VALUES (:username, :email, :role);",
PARAM(oatpp::String, username),
PARAM(oatpp::String, email),
PARAM(oatpp::Enum<UserRoles>::AsString, role))
```
#### Using API Client
## Frequently Asked Questions
```cpp
auto response = userService->getUserById(id);
auto user = response->readBodyToDto<oatpp::Object<UserDto>>(objectMapper);
```
### Q: "Oat++" name?
### Object Mapping
- "Oat" is something light, organic, and green. It can be easily cooked and consumed with no effort.
- "++" gives a hint that it is "something" for C++.
For more info see [Data Transfer Object (DTO)](https://oatpp.io/docs/components/dto/).
### Q: What is the main area of Oat++ application?
#### Declare DTO
Oat++ is used for many different purposes, from building REST APIs that run on embedded devices to
building microservices and highly-loaded cloud applications.
```cpp
class UserDto : public oatpp::DTO {
But the majority of use cases appears to be in **IoT** and **Robotics**.
DTO_INIT(UserDto, DTO)
### Q: How portable is Oat++?
DTO_FIELD(Int64, id);
DTO_FIELD(String, name);
Theoretically, Oat++ can be **easily** ported everywhere where you have **threads** and **network stack**.
With an additional comparably small effort, it can be ported almost everywhere depending on how
much you strip it and what would be the final binary size.
};
```
See [supported platforms](https://oatpp.io/supported-platforms/) for additional info.
#### Serialize DTO Using ObjectMapper
### Q: What is the size of a minimal Oat++ application?
```cpp
using namespace oatpp::parser::json::mapping;
About **1Mb**, depending on C/C++ std-lib and oatpp version.
auto user = UserDto::createShared();
user->id = 1;
user->name = "Ivan";
### Q: Which Oat++ API to choose, Simple or Async?
auto objectMapper = ObjectMapper::createShared();
auto json = objectMapper->writeToString(user);
```
Always choose **Simple API** wherever possible. Simple API is more developed and makes the code cleaner.
Output:
Async API is designed for small, specific tasks that run at high concurrency levels ex.:
- Serving file downloads to a large number of concurrent users (1K users and more).
- Streaming to a large number of clients (1K or more).
- Websocket Chat servers.
```json
{
"id": 1,
"name": "Ivan"
}
```
For all other purposes use simple API.
#### Serialize/Deserialize Data In Free Form
## Examples
While DTO objects apply strict rules on data ser/de, you can also
serialize/deserialize data in free form using type `oatpp::Any`.
### REST-API
```cpp
oatpp::Fields<oatpp::Any> map = {
{"title", oatpp::String("Hello Any!")},
{"listOfAny",
oatpp::List<oatpp::Any>({
oatpp::Int32(32),
oatpp::Float32(0.32),
oatpp::Boolean(true)
})
}
};
- [REST Service](https://github.com/oatpp/example-crud) - A complete example of a "CRUD" service (UserService) built with Oat++. REST + Swagger-UI + SQLite.
- [REST Client](https://github.com/oatpp/example-api-client) - Example project of how-to use Retrofit-like client wrapper (ApiClient) and how it works.
auto json = mapper->writeToString(map);
```
### WebSocket
Output:
```json
{
"title": "Hello Any!",
"listOfAny": [
32,
0.3199999928474426,
true
]
}
```
### Examples:
#### REST-API
- [ApiClient-Demo](https://github.com/oatpp/example-api-client) - Example project of how-to use Retrofit-like client wrapper (ApiClient) and how it works.
- [AsyncApi](https://github.com/oatpp/example-async-api) - Example project of how-to use asynchronous API for handling large number of simultaneous connections.
- [CRUD](https://github.com/oatpp/example-crud) - Example project of how-to create basic CRUD endpoints.
#### WebSocket
- [Can-Chat](https://github.com/lganzzzo/canchat) - Feature-complete rooms-based chat for tens of thousands users. Client plus Server.
- [Can Chat](https://github.com/lganzzzo/canchat) - Feature-complete rooms-based chat for tens of thousands users. Client plus Server.
- [WebSocket](https://github.com/oatpp/example-websocket) - Collection of oatpp WebSocket examples.
- [YUV-Websocket-Stream](https://github.com/oatpp/example-yuv-websocket-stream) - Example project how-to create a YUV image stream from a V4L device (i.E. Webcam) using websockets.
- [YUV Websocket Stream](https://github.com/oatpp/example-yuv-websocket-stream) - Example project how-to create a YUV image stream from a V4L device (i.E. Webcam) using websockets.
### Databases
- [SQLite](https://github.com/oatpp/example-crud) - A complete example of a "CRUD" service. REST + Swagger-UI + SQLite.
- [PostgreSQL](https://github.com/oatpp/example-postgresql) - Example of a production-grade entity service storing information in PostgreSQL. With Swagger-UI and configuration profiles.
- [MongoDB](https://github.com/oatpp/example-mongodb) - Example project how to work with MongoDB using **oatpp-mongo** mondule. Project is a web-service with basic CRUD and Swagger-UI.
### IoT
- [Example-IoT-Hue](https://github.com/oatpp/example-iot-hue-ssdp) - Example project how-to create an Philips Hue compatible REST-API that is discovered and controllable by Hue compatible Smart-Home devices like Amazon Alexa or Google Echo.
#### Streaming
### Streaming
- [Media-Stream (Http-Live-Streaming)](https://github.com/oatpp/example-hls-media-stream) - Example project of how-to build HLS-streaming server using oat++ Async-API.
- [YUV-Websocket-Stream](https://github.com/oatpp/example-yuv-websocket-stream) - Example project how-to create a YUV image stream from a V4L device (i.E. Webcam) using websockets.
- [HTTP Live Streaming Server](https://github.com/oatpp/example-hls-media-stream) - Example project on how to build an HLS-streaming server using Oat++ asynchronous API.
- [YUV Websocket Stream](https://github.com/oatpp/example-yuv-websocket-stream) - Example project how-to create a YUV image stream from a V4L device (i.E. Webcam) using websockets.
#### TLS
### TLS
- [TLS-Libressl](https://github.com/oatpp/example-libressl) - Example project how-to setup secure connection and serve via HTTPS.
- [TLS With Libressl](https://github.com/oatpp/example-libressl) - Example project how-to setup secure connection and serve via HTTPS.
#### Microservices
### Microservices
- [Consul](https://github.com/oatpp/example-consul) - Example project of how-to use oatpp::consul::Client. Integration with Consul.
- [Consul Integration](https://github.com/oatpp/example-consul) - Example project on how to use [oatpp::consul::Client](https://oatpp.io/api/latest/oatpp-consul/rest/Client/). Consul integration.
- [Microservices](https://github.com/oatpp/example-microservices) - Example project on how to build microservices with Oat++,
and example on how to consolidate those microservices using [monolithization](https://oatpp.io/docs/monolithization/) technique.
#### Databases
- [MongoDB](https://github.com/oatpp/example-mongodb) - Example project how to work with MongoDB using [oatpp-mongo](https://github.com/oatpp/oatpp-mongo) mondule.
Project is a web-service with basic CRUD and Swagger-UI.
- [PostgreSQL](https://github.com/oatpp/example-postgresql) - Example of a production grade entity service storing information in PostgreSQL. With Swagger-UI and configuration profiles.
### Asynchronous API
- [Async Service](https://github.com/oatpp/example-async-api) - Example project on how to use asynchronous API to handle a large number of simultaneous connections.

View File

@ -4,11 +4,11 @@
# https://aka.ms/yaml
jobs:
- job: ubuntu_16_04_mem_pool_on
displayName: 'Build - Ubuntu 16.04 - With Memory Pool'
- job: ubuntu_20_04_mem_pool_on
displayName: 'Build - Ubuntu 20.04 - With Memory Pool'
continueOnError: false
pool:
vmImage: 'Ubuntu 16.04'
vmImage: 'ubuntu-20.04'
workspace:
clean: all
steps:
@ -25,11 +25,11 @@ jobs:
displayName: 'Test'
workingDirectory: build
- job: ubuntu_16_04_mem_pool_off
displayName: 'Build - Ubuntu 16.04 - No Memory Pool'
- job: ubuntu_20_04_mem_pool_off
displayName: 'Build - Ubuntu 20.04 - No Memory Pool'
continueOnError: false
pool:
vmImage: 'Ubuntu 16.04'
vmImage: 'ubuntu-20.04'
workspace:
clean: all
steps:

View File

@ -9,6 +9,7 @@ Contents:
- [Object-Mapping - Type Interpretations](#type-interpretations)
- [The new Oat++ ORM](#orm)
- [Changes in oatpp::network Namespace](#changes-in-oatppnetwork-namespace)
- [New Modules](#new-modules)
## Continuous Multipart Streaming
@ -129,7 +130,7 @@ namespace __class {
static oatpp::Type* getType(){
static Type type(
CLASS_ID, nullptr, nullptr, nullptr, nullptr,
CLASS_ID, nullptr, nullptr,
{
{"my-types", new Inter()} //<-- Add type interpretation
}
@ -170,6 +171,11 @@ auto pointClone = mapper.readFromString<Point>(json); // Deserialize Point
The main feature of the `1.2.0` release is the new ORM Framework.
For details see - [Object-Relational Mapping (ORM) framework](https://oatpp.io/docs/components/orm/)
### ORM Adaptors
- [oatpp-sqlite](https://github.com/oatpp/oatpp-sqlite) - SQLite adapter for Oat++ ORM. Full support.
- [oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql) - Oat++ ORM adapter for PostgreSQL. Alpha version.
## Changes in oatpp::network Namespace
### Moved and Renamed
@ -219,3 +225,10 @@ oatpp::network::tcp::client::ConnectionProvider::createShared(
true /* use extended connections */
);
```
## New Modules
- [oatpp-sqlite](https://github.com/oatpp/oatpp-sqlite) - SQLite adapter for Oat++ ORM. Full support.
- [oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql) - Oat++ ORM adapter for PostgreSQL. Alpha version.
- [oatpp-protobuf](https://github.com/oatpp/oatpp-protobuf) - Protobuf integration with oatpp object-mapping framework. Use
protobuf objects as regular oatpp DTOs. Serialize/Deserialize protobuf object to/from JSON, BSON and other oatpp supported formats.

222
changelog/1.2.5.md Normal file
View File

@ -0,0 +1,222 @@
# Oat++ 1.2.5
Previous release - [1.2.0](1.2.0.md)
Feel free to ask questions - [Chat on Gitter!](https://gitter.im/oatpp-framework/Lobby)
Contents:
- [Introduce ResponseInterceptor](#introduce-responseinterceptor)
- [Enable Global CORS](#enable-global-cors)
- [Headers Multimap](#headers-multimap)
- [Better Router API](#better-router-api)
- [ORM Clean Section](#orm-clean-section)
- [ORM PostgreSQL - Arrays Support](#orm-postgresql---arrays-support)
- [Swagger-UI Example Values](#swagger-ui-example-values)
- [New Modules](#new-modules)
## Introduce ResponseInterceptor
### Declare Response Interceptor
```cpp
#include "oatpp/web/server/interceptor/ResponseInterceptor.hpp"
class MyResponseInterceptor : public ResponseInterceptor {
public:
std::shared_ptr<OutgoingResponse> intercept(const std::shared_ptr<IncomingRequest>& request,
const std::shared_ptr<OutgoingResponse>& response) override
{
// TODO modify response or create a new one
return response; // return modified response
// returning nullptr will result in an error
}
};
```
### Register global request interceptor
```cpp
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router);
/* Add MyResponseInterceptor */
connectionHandler->addResponseInterceptor(std::make_shared<MyResponseInterceptor>());
return connectionHandler;
}());
```
## Enable Global CORS
To enable global CORS for all endpoints:
- Add **Request** Interceptor - `oatpp::web::server::interceptor::AllowOptionsGlobal` to `ConnectionHandler`.
- Add **Response** Interceptor - `atpp::web::server::interceptor::AllowCorsGlobal` to `ConnectionHandler`.
```cpp
#include "oatpp/web/server/interceptor/AllowCorsGlobal.hpp"
...
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router);
/* Add CORS-enabling interceptors */
connectionHandler->addRequestInterceptor(std::make_shared<oatpp::web::server::interceptor::AllowOptionsGlobal>());
connectionHandler->addResponseInterceptor(std::make_shared<oatpp::web::server::interceptor::AllowCorsGlobal>());
return connectionHandler;
}());
```
## Headers Multimap
Now headers are stored using [std::multimap](https://en.cppreference.com/w/cpp/container/multimap) and can store multiple entries with the same key.
Put multiple headers:
```cpp
auto response = createResponse(Status::CODE_200, "");
response->putHeader("Set-Cookie", "...");
response->putHeader("Set-Cookie", "...");
return response;
```
Log all "Set-Cookie" headers:
```cpp
const auto& map = headers.getAll();
auto itlow = map.lower_bound("Set-Cookie");
auto itup = map.upper_bound("Set-Cookie");
for(auto it = itlow; it != itup; it ++) {
oatpp::String value = it->second.toString();
OATPP_LOGD("Header", "Set-Cookie: %s", value->c_str());
}
```
## Better Router API
Now Router class is a template and can store any value-types and not only `RequestHandler`s.
Example use-case - check if endpoint should require authorization:
**Add Routs**
```cpp
oatpp::web::server::HttpRouterTemplate<bool> authEndpoints;
authEndpoint.route("POST", "login", false); // DO NOT require auth for /login path
authEndpoint.route("POST", "auth", false); // DO NOT require auth for /auth path
authEndpoint.route("GET", "*", true); // require auth for all GET
authEndpoint.route("POST", "*", true); // require auth for all POST
authEndpoint.route("OPTIONS", "*", false); // DO NOT require auth for OPTIONS
```
**Check Auth**
```cpp
auto r = authEndpoints.getRoute(request->getStartingLine().method, request->getStartingLine().path);
if(r && r.getEndpoint() == true) {
// check auth
}
```
## ORM Clean Section
For modules:
- [oatpp-sqlite](https://github.com/oatpp/oatpp-sqlite)
- [oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql)
Now it's possible to declare a "clean section" - a section that is untouched by DSL processor.
Clean section begins with `<!!` and ends with `!!>`.
**Note:** `<!!` and `!!>` char sequences are ignored inside string.
### Example
Such query:
```cpp
QUERY(selectUserName,
"SELECT <!! name::varchar !!> FROM users WHERE userId=:userId",
PARAM(String, userId))
```
Will be processed as follows:
```sql
SELECT name::varchar FROM users WHERE userId="<user-id-value>"
```
Note: unlike the `:userId` the `:varchar` char-sequence wasn't interpreted as a template parameter (unlike the `:userId`).
## ORM PostgreSQL - Arrays Support
[oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql) now supports arrays.
More about PostgreSQL arrays - read [here](https://www.postgresql.org/docs/13/arrays.html)
## Swagger-UI Example Values
Now it's possible to add example-values to `RequestBody`, `Response`, and `Parameters` (Path, Headers, Queries)
### Add Consumes Examples
```cpp
ENDPOINT_INFO(myEndpoint) {
info->addConsumes<Object<MyDto>>("application/json")
.addExample("example_1", MyDto::createShared(... /* params here */ ))
.addExample("example_2", MyDto::createShared(... /* params here */ ))
.addExample("example_3", MyDto::createShared(... /* params here */ ));
}
```
### Add Response Examples
```cpp
ENDPOINT_INFO(myEndpoint) {
info->addResponse<Object<MyDto>>(Status::CODE_200, "application/json")
.addExample("Successful Response_1", MyDto::createShared(... /* params */ ));
info->addResponse<Object<ErrorDto>>(Status::CODE_404, "application/json")
.addExample("Error - Not found", ErrorDto::createShared(404, "Not Found"));
info->addResponse<Object<ErrorDto>>(Status::CODE_500, "application/json")
.addExample("Error - DB Connection", ErrorDto::createShared(500, "Can't connect to DB"))
.addExample("Error - Unknown", ErrorDto::createShared(500, "Unknown Error"));
}
```
### Add Parameter Examples
```cpp
ENDPOINT_INFO(myEndpoint) {
info->pathParams["userRole"]
.addExample("Admin", oatpp::Enum<UserRole>(UserRole::ADMIN))
.addExample("Guest", oatpp::Enum<UserRole>(UserRole::GUEST));
}
```
## New Modules
- [oatpp-openssl](https://github.com/oatpp/oatpp-openssl) - TLS adaptor for OpenSSL (Recommended to use).

324
changelog/1.3.0.md Normal file
View File

@ -0,0 +1,324 @@
# 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)
- [TemporaryFile](#temporaryfile)
- [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.
## TemporaryFile
Introduce `oatpp::data::share::TemporaryFile`.
Use-case:
Temporary file resolves concurrency issues during file uploads.
Also, a temporary file ensures that partially uploaded (due to errors/exceptions) resources will be automatically deleted at the end of the block.
```cpp
ENDPOINT("POST", "/upload", upload,
REQUEST(std::shared_ptr<IncomingRequest>, request))
{
oatpp::data::share::TemporaryFile tmp("/tmp"); // create random file in '/tmp' folder
auto stream = tmp.openOutputStream();
request->transferBody(&stream); // transfer body to temporary file
tmp.moveFile("/path/to/permanent/storage/avatar.png"); // move file to permanent storage
return createResponse(Status::CODE_200, "OK");
}
```
## 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`.

36
cmake/msvc-runtime.cmake Normal file
View File

@ -0,0 +1,36 @@
macro(configure_msvc_runtime)
if(MSVC)
# Set compiler options.
set(variables
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(OATPP_MSVC_LINK_STATIC_RUNTIME)
message(STATUS "MSVC: using statically-linked runtime (/MT and /MTd).")
foreach(variable ${variables})
if(${variable} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
endif()
endforeach()
else()
message(STATUS "MSVC: using dynamically-linked runtime (/MD and /MDd).")
foreach(variable ${variables})
if(${variable} MATCHES "/MT")
string(REGEX REPLACE "/MT" "/MD" ${variable} "${${variable}}")
endif()
endforeach()
endif()
foreach(variable ${variables})
set(${variable} "${${variable}}" CACHE STRING "MSVC_${variable}" FORCE)
endforeach()
endif()
endmacro(configure_msvc_runtime)

View File

@ -0,0 +1,27 @@
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include "oatpp/core/macro/codegen.hpp"
typedef oatpp::parser::Caret ParsingCaret;
typedef oatpp::parser::json::mapping::Serializer Serializer;
typedef oatpp::parser::json::mapping::Deserializer Deserializer;
#include OATPP_CODEGEN_BEGIN(DTO)
class EmptyDto : public oatpp::DTO {
DTO_INIT(EmptyDto, DTO)
};
class Test1 : public oatpp::DTO {
DTO_INIT(Test1, DTO)
DTO_FIELD(String, strF);
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
oatpp::String input(reinterpret_cast<const char*>(data), size);
oatpp::parser::json::mapping::ObjectMapper mapper;
try {
mapper.readFromString<oatpp::Object<Test1>>(input);
} catch(...) {}
return 0;
}

View File

@ -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
@ -107,16 +105,22 @@ add_library(oatpp
oatpp/core/data/share/MemoryLabel.hpp
oatpp/core/data/share/StringTemplate.cpp
oatpp/core/data/share/StringTemplate.hpp
oatpp/core/data/share/TemporaryFile.cpp
oatpp/core/data/share/TemporaryFile.hpp
oatpp/core/data/stream/BufferStream.cpp
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 +128,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 +137,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 +176,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
@ -264,8 +281,10 @@ add_library(oatpp
oatpp/web/server/handler/AuthorizationHandler.hpp
oatpp/web/server/handler/ErrorHandler.cpp
oatpp/web/server/handler/ErrorHandler.hpp
oatpp/web/server/handler/Interceptor.cpp
oatpp/web/server/handler/Interceptor.hpp
oatpp/web/server/interceptor/AllowCorsGlobal.cpp
oatpp/web/server/interceptor/AllowCorsGlobal.hpp
oatpp/web/server/interceptor/RequestInterceptor.hpp
oatpp/web/server/interceptor/ResponseInterceptor.hpp
oatpp/web/url/mapping/Pattern.cpp
oatpp/web/url/mapping/Pattern.hpp
oatpp/web/url/mapping/Router.hpp
@ -276,6 +295,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)
@ -320,6 +342,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)

View File

@ -36,6 +36,8 @@ void UnitTest::run(v_int32 times) {
v_counter objectsCount = base::Environment::getObjectsCount();
v_counter objectsCreated = base::Environment::getObjectsCreated();
before();
v_int64 ticks = base::Environment::getMicroTickCount();
@ -44,6 +46,8 @@ void UnitTest::run(v_int32 times) {
}
v_int64 millis = base::Environment::getMicroTickCount() - ticks;
after();
v_counter leakingObjects = base::Environment::getObjectsCount() - objectsCount;
v_counter objectsCreatedPerTest = base::Environment::getObjectsCreated() - objectsCreated;

View File

@ -25,7 +25,9 @@
#ifndef oatpp_test_UnitTest_hpp
#define oatpp_test_UnitTest_hpp
#include <functional>
#include "oatpp/core/base/Environment.hpp"
#include "oatpp/core/macro/basic.hpp"
namespace oatpp { namespace test {
@ -67,6 +69,14 @@ public:
* Override this method. It should contain test logic.
*/
virtual void onRun() = 0;
/**
* Optionally override this method. It should contain logic run before all test iterations.
*/
virtual void before(){};
/**
* Optionally override this method. It should contain logic run after all test iterations.
*/
virtual void after(){};
/**
* Run this test repeatedly for specified number of times.
@ -81,14 +91,22 @@ public:
};
#define OATPP_RUN_TEST_0(TEST) \
oatpp::test::UnitTest::runTest<TEST>(1)
#define OATPP_RUN_TEST_1(TEST, N) \
oatpp::test::UnitTest::runTest<TEST>(N)
/**
* Convenience macro to run test. <br>
* Usage Example:<br>
* `OATPP_RUN_TEST(oatpp::test::web::FullTest);`
* Running the test 10 times:
* `OATPP_RUN_TEST(oatpp::test::web::FullTest, 10);`
*/
#define OATPP_RUN_TEST(TEST) \
oatpp::test::UnitTest::runTest<TEST>(1)
#define OATPP_RUN_TEST(...) \
OATPP_MACRO_EXPAND(OATPP_MACRO_MACRO_BINARY_SELECTOR(OATPP_RUN_TEST_, (__VA_ARGS__)) (__VA_ARGS__))
}}
#endif /* oatpp_test_UnitTest_hpp */

View File

@ -65,7 +65,7 @@ public:
* @param controller
*/
void addController(const std::shared_ptr<ApiController>& controller) {
controller->addEndpointsToRouter(m_router);
m_router->route(controller->getEndpoints());
m_controllers.push_back(controller);
}
@ -89,21 +89,26 @@ public:
std::atomic<bool> running(true);
std::mutex timeoutMutex;
std::condition_variable timeoutCondition;
bool runConditionForLambda = true;
m_server = std::make_shared<oatpp::network::Server>(m_connectionProvider, m_connectionHandler);
OATPP_LOGD("\033[1;34mClientServerTestRunner\033[0m", "\033[1;34mRunning server on port %s. Timeout %lld(micro)\033[0m",
m_connectionProvider->getProperty("port").toString()->c_str(),
timeout.count());
std::thread serverThread([this]{
m_server->run();
std::function<bool()> condition = [&runConditionForLambda](){
return runConditionForLambda;
};
std::thread serverThread([&condition, this]{
m_server->run(condition);
});
std::thread clientThread([this, &lambda]{
std::thread clientThread([&runConditionForLambda, this, &lambda]{
lambda();
m_server->stop();
// m_server->stop();
runConditionForLambda = false;
m_connectionHandler->stop();
m_connectionProvider->stop();

View File

@ -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"

View File

@ -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"

View File

@ -118,7 +118,7 @@ OATPP_MACRO_PARAM_USECASE_BODY X
const oatpp::data::share::StringTemplate Z_QUERY_TEMPLATE_##NAME = \
this->parseQueryTemplate(#NAME, QUERY_TEXT, {}, false); \
\
std::shared_ptr<oatpp::orm::QueryResult> NAME(const std::shared_ptr<oatpp::orm::Connection>& connection = nullptr) { \
std::shared_ptr<oatpp::orm::QueryResult> NAME(const oatpp::provider::ResourceHandle<oatpp::orm::Connection>& connection = nullptr) { \
std::unordered_map<oatpp::String, oatpp::Void> __params; \
return this->execute(Z_QUERY_TEMPLATE_##NAME, __params, connection); \
}
@ -139,7 +139,7 @@ const oatpp::data::share::StringTemplate Z_QUERY_TEMPLATE_##NAME = Z_QUERY_TEMPL
\
std::shared_ptr<oatpp::orm::QueryResult> NAME( \
OATPP_MACRO_FOREACH(OATPP_MACRO_DB_CLIENT_PARAM_PUT_DECL, __VA_ARGS__) \
const std::shared_ptr<oatpp::orm::Connection>& connection = nullptr \
const oatpp::provider::ResourceHandle<oatpp::orm::Connection>& connection = nullptr \
) { \
std::unordered_map<oatpp::String, oatpp::Void> __params; \
OATPP_MACRO_FOREACH(OATPP_MACRO_DB_CLIENT_PARAM_PUT, __VA_ARGS__) \

View File

@ -186,6 +186,17 @@ if(!__param_validation_check_##NAME){ \
"'. Expected type is '" #TYPE "'"); \
}
#define OATPP_MACRO_API_CONTROLLER_QUERY_3(TYPE, NAME, QUALIFIER, DEFAULT) \
const auto& __param_str_val_##NAME = __request->getQueryParameter(QUALIFIER, DEFAULT); \
bool __param_validation_check_##NAME; \
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
if(!__param_validation_check_##NAME){ \
return ApiController::handleError(Status::CODE_400, \
oatpp::String("Invalid QUERY parameter '") + \
QUALIFIER + \
"'. Expected type is '" #TYPE "'"); \
}
#define OATPP_MACRO_API_CONTROLLER_QUERY(TYPE, PARAM_LIST) \
OATPP_MACRO_API_CONTROLLER_MACRO_SELECTOR(OATPP_MACRO_API_CONTROLLER_QUERY_, TYPE, OATPP_MACRO_UNFOLD_VA_ARGS PARAM_LIST)
@ -197,6 +208,9 @@ info->queryParams.add(#NAME, TYPE::Class::getType());
#define OATPP_MACRO_API_CONTROLLER_QUERY_INFO_2(TYPE, NAME, QUALIFIER) \
info->queryParams.add(QUALIFIER, TYPE::Class::getType());
#define OATPP_MACRO_API_CONTROLLER_QUERY_INFO_3(TYPE, NAME, QUALIFIER, DEFAULT) \
info->queryParams.add(QUALIFIER, TYPE::Class::getType());
#define OATPP_MACRO_API_CONTROLLER_QUERY_INFO(TYPE, PARAM_LIST) \
OATPP_MACRO_API_CONTROLLER_MACRO_SELECTOR(OATPP_MACRO_API_CONTROLLER_QUERY_INFO_, TYPE, OATPP_MACRO_UNFOLD_VA_ARGS PARAM_LIST)
@ -209,11 +223,18 @@ const auto& OATPP_MACRO_FIRSTARG PARAM_LIST = __request->readBodyToString();
#define OATPP_MACRO_API_CONTROLLER_BODY_STRING_INFO(TYPE, PARAM_LIST) \
info->body.name = OATPP_MACRO_FIRSTARG_STR PARAM_LIST; \
info->body.type = oatpp::data::mapping::type::__class::String::getType();
info->body.required = true; \
info->body.type = oatpp::data::mapping::type::__class::String::getType(); \
if(getDefaultObjectMapper()) { \
info->bodyContentType = getDefaultObjectMapper()->getInfo().http_content_type; \
}
// BODY_DTO MACRO // ------------------------------------------------------
#define OATPP_MACRO_API_CONTROLLER_BODY_DTO(TYPE, PARAM_LIST) \
if(!getDefaultObjectMapper()) { \
return ApiController::handleError(Status::CODE_500, "ObjectMapper was NOT set. Can't deserialize the request body."); \
} \
const auto& OATPP_MACRO_FIRSTARG PARAM_LIST = \
__request->readBodyToDto<TYPE>(getDefaultObjectMapper().get()); \
if(!OATPP_MACRO_FIRSTARG PARAM_LIST) { \
@ -224,7 +245,11 @@ if(!OATPP_MACRO_FIRSTARG PARAM_LIST) { \
#define OATPP_MACRO_API_CONTROLLER_BODY_DTO_INFO(TYPE, PARAM_LIST) \
info->body.name = OATPP_MACRO_FIRSTARG_STR PARAM_LIST; \
info->body.type = TYPE::Class::getType();
info->body.required = true; \
info->body.type = TYPE::Class::getType(); \
if(getDefaultObjectMapper()) { \
info->bodyContentType = getDefaultObjectMapper()->getInfo().http_content_type; \
}
// FOR EACH // ------------------------------------------------------
@ -250,15 +275,15 @@ OATPP_MACRO_API_CONTROLLER_PARAM_INFO X
#define ENDPOINT_INFO(NAME) \
\
std::shared_ptr<Endpoint::Info> Z__ENDPOINT_CREATE_ADDITIONAL_INFO_##NAME() { \
std::shared_ptr<oatpp::web::server::api::Endpoint::Info> Z__ENDPOINT_CREATE_ADDITIONAL_INFO_##NAME() { \
auto info = Z__EDNPOINT_INFO_GET_INSTANCE_##NAME(); \
Z__ENDPOINT_ADD_INFO_##NAME(info); \
return info; \
} \
\
const std::shared_ptr<Endpoint::Info> Z__ENDPOINT_ADDITIONAL_INFO_##NAME = Z__ENDPOINT_CREATE_ADDITIONAL_INFO_##NAME(); \
const std::shared_ptr<oatpp::web::server::api::Endpoint::Info> Z__ENDPOINT_ADDITIONAL_INFO_##NAME = Z__ENDPOINT_CREATE_ADDITIONAL_INFO_##NAME(); \
\
void Z__ENDPOINT_ADD_INFO_##NAME(const std::shared_ptr<Endpoint::Info>& info)
void Z__ENDPOINT_ADD_INFO_##NAME(const std::shared_ptr<oatpp::web::server::api::Endpoint::Info>& info)
// ENDPOINT MACRO // ------------------------------------------------------
@ -274,10 +299,10 @@ static typename std::shared_ptr<Handler<T>> Z__ENDPOINT_HANDLER_GET_INSTANCE_##N
return handler; \
} \
\
std::shared_ptr<Endpoint::Info> Z__EDNPOINT_INFO_GET_INSTANCE_##NAME() { \
std::shared_ptr<Endpoint::Info> info = getEndpointInfo(#NAME); \
std::shared_ptr<oatpp::web::server::api::Endpoint::Info> Z__EDNPOINT_INFO_GET_INSTANCE_##NAME() { \
std::shared_ptr<oatpp::web::server::api::Endpoint::Info> info = getEndpointInfo(#NAME); \
if(!info){ \
info = Endpoint::Info::createShared(); \
info = oatpp::web::server::api::Endpoint::Info::createShared(); \
setEndpointInfo(#NAME, info); \
} \
return info; \
@ -296,7 +321,7 @@ EndpointInfoBuilder Z__CREATE_ENDPOINT_INFO_##NAME = [this](){ \
return info; \
}; \
\
const std::shared_ptr<Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
const std::shared_ptr<oatpp::web::server::api::Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
Z__ENDPOINT_HANDLER_GET_INSTANCE_##NAME(this), \
Z__CREATE_ENDPOINT_INFO_##NAME);
@ -326,7 +351,7 @@ auto info = Z__EDNPOINT_INFO_GET_INSTANCE_##NAME(); \
return info; \
}; \
\
const std::shared_ptr<Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
const std::shared_ptr<oatpp::web::server::api::Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
Z__ENDPOINT_HANDLER_GET_INSTANCE_##NAME(this), \
Z__CREATE_ENDPOINT_INFO_##NAME);
@ -428,10 +453,10 @@ static typename std::shared_ptr<Handler<T>> Z__ENDPOINT_HANDLER_GET_INSTANCE_##N
return handler; \
} \
\
std::shared_ptr<Endpoint::Info> Z__EDNPOINT_INFO_GET_INSTANCE_##NAME() { \
std::shared_ptr<Endpoint::Info> info = getEndpointInfo(#NAME); \
std::shared_ptr<oatpp::web::server::api::Endpoint::Info> Z__EDNPOINT_INFO_GET_INSTANCE_##NAME() { \
std::shared_ptr<oatpp::web::server::api::Endpoint::Info> info = getEndpointInfo(#NAME); \
if(!info){ \
info = Endpoint::Info::createShared(); \
info = oatpp::web::server::api::Endpoint::Info::createShared(); \
setEndpointInfo(#NAME, info); \
} \
return info; \
@ -451,7 +476,7 @@ EndpointInfoBuilder Z__CREATE_ENDPOINT_INFO_##NAME = [this](){ \
return info; \
}; \
\
const std::shared_ptr<Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
const std::shared_ptr<oatpp::web::server::api::Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints, \
Z__ENDPOINT_HANDLER_GET_INSTANCE_##NAME(this), \
Z__CREATE_ENDPOINT_INFO_##NAME);

View 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)

View File

@ -7,6 +7,7 @@
*
*
* 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.
@ -22,4 +23,10 @@
*
***************************************************************************/
#include "Interceptor.hpp"
#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

View File

@ -46,9 +46,10 @@ EndpointInfoBuilder Z__CREATE_ENDPOINT_INFO_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME
return info; \
}; \
\
const std::shared_ptr<Endpoint> Z__ENDPOINT_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME = createEndpoint(m_endpoints, \
Z__ENDPOINT_HANDLER_GET_INSTANCE_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME(this), \
Z__CREATE_ENDPOINT_INFO_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME);\
const std::shared_ptr<oatpp::web::server::api::Endpoint> \
Z__ENDPOINT_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME = createEndpoint(m_endpoints, \
Z__ENDPOINT_HANDLER_GET_INSTANCE_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME(this), \
Z__CREATE_ENDPOINT_INFO_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME);\
\
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response> \
Z__PROXY_METHOD_Z__CORS_OPTIONS_DECL_##ENDPOINTNAME(const std::shared_ptr<oatpp::web::protocol::http::incoming::Request>& __request) \
@ -151,6 +152,7 @@ OATPP_MACRO_API_CONTROLLER_ADD_CORS_OPTIONS_DECL(ENDPOINTNAME) { \
ENDPOINT_INTERCEPTOR(ENDPOINTNAME, CORS) { \
auto resp = (this->*intercepted)(request); \
OATPP_MACRO_API_CONTROLLER_ADD_CORS_BODY(ORIGIN, METHODS, HEADERS, MAX_AGE) \
return resp; \
} \
OATPP_MACRO_API_CONTROLLER_ADD_CORS_OPTIONS_DECL(ENDPOINTNAME) { \
auto resp = createResponse(Status::CODE_204, ""); \

View File

@ -47,8 +47,6 @@ private: \
return &map; \
} \
public: \
\
TYPE_NAME() = default; \
\
template<typename ... Args> \
static Wrapper createShared(Args... args){ \

View File

@ -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;

View File

@ -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)
{}
@ -168,23 +176,16 @@ CoroutineStarter::CoroutineStarter(CoroutineStarter&& other)
}
CoroutineStarter::~CoroutineStarter() {
if(m_first != nullptr) {
auto curr = m_first;
while(curr != nullptr) {
AbstractCoroutine* next = nullptr;
if(curr->m_parentReturnAction.m_type == Action::TYPE_COROUTINE) {
next = curr->m_parentReturnAction.m_data.coroutine;
}
delete curr;
curr = next;
}
}
freeCoroutines();
}
/*
* Move assignment operator.
*/
CoroutineStarter& CoroutineStarter::operator=(CoroutineStarter&& other) {
if (this == std::addressof(other)) return *this;
freeCoroutines();
m_first = other.m_first;
m_last = other.m_last;
other.m_first = nullptr;
@ -216,6 +217,21 @@ CoroutineStarter& CoroutineStarter::next(CoroutineStarter&& starter) {
return *this;
}
void CoroutineStarter::freeCoroutines()
{
if (m_first != nullptr) {
auto curr = m_first;
while (curr != nullptr) {
AbstractCoroutine* next = nullptr;
if (curr->m_parentReturnAction.m_type == Action::TYPE_COROUTINE) {
next = curr->m_parentReturnAction.m_data.coroutine;
}
delete curr;
curr = next;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CoroutineHandle

View File

@ -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;.
@ -341,6 +361,11 @@ class CoroutineStarter {
private:
AbstractCoroutine* m_first;
AbstractCoroutine* m_last;
private:
void freeCoroutines();
public:
/**
@ -597,8 +622,8 @@ public:
* @return - &id:oatpp::async::CoroutineStarter;.
*/
template<typename ...ConstructorArgs>
static CoroutineStarter start(ConstructorArgs... args) {
return new T(args...);
static CoroutineStarter start(ConstructorArgs&&... args) {
return new T(std::forward<ConstructorArgs>(args)...);
}
/**
@ -686,6 +711,9 @@ public:
* Move assignment operator.
*/
StarterForResult& operator=(StarterForResult&& other) {
if (this == std::addressof(other)) return *this;
delete m_coroutine;
m_coroutine = other.m_coroutine;
other.m_coroutine = nullptr;
return *this;
@ -759,7 +787,7 @@ public:
* @param ptr - pointer of the function to call.
* @return - Action.
*/
virtual Action call(const AbstractCoroutine::FunctionPtr& ptr) override {
Action call(const AbstractCoroutine::FunctionPtr& ptr) override {
Function f = static_cast<Function>(ptr);
return (static_cast<T*>(this)->*f)();
}

View File

@ -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;
}
}}

View File

@ -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);
};

View File

@ -54,12 +54,12 @@ void Executor::SubmissionProcessor::run() {
void Executor::SubmissionProcessor::pushTasks(oatpp::collection::FastQueue<CoroutineHandle>& tasks) {
(void)tasks;
std::runtime_error("[oatpp::async::Executor::SubmissionProcessor::pushTasks]: Error. This method does nothing.");
throw std::runtime_error("[oatpp::async::Executor::SubmissionProcessor::pushTasks]: Error. This method does nothing.");
}
void Executor::SubmissionProcessor::pushOneTask(CoroutineHandle* task) {
(void)task;
std::runtime_error("[oatpp::async::Executor::SubmissionProcessor::pushOneTask]: Error. This method does nothing.");
throw std::runtime_error("[oatpp::async::Executor::SubmissionProcessor::pushOneTask]: Error. This method does nothing.");
}
void Executor::SubmissionProcessor::stop() {
@ -94,7 +94,7 @@ Executor::Executor(v_int32 processorWorkersCount, v_int32 ioWorkersCount, v_int3
m_allWorkers.insert(m_allWorkers.end(), m_processorWorkers.begin(), m_processorWorkers.end());
std::vector<std::shared_ptr<worker::Worker>> ioWorkers;
ioWorkers.reserve(ioWorkersCount);
switch(ioWorkerType) {
case IO_WORKER_TYPE_NAIVE: {
@ -119,6 +119,7 @@ Executor::Executor(v_int32 processorWorkersCount, v_int32 ioWorkersCount, v_int3
linkWorkers(ioWorkers);
std::vector<std::shared_ptr<worker::Worker>> timerWorkers;
timerWorkers.reserve(timerWorkersCount);
for(v_int32 i = 0; i < timerWorkersCount; i++) {
timerWorkers.push_back(std::make_shared<worker::TimerWorker>());
}
@ -233,10 +234,10 @@ void Executor::stop() {
}
v_int32 Executor::getTasksCount() {
v_int32 result = 0;
for(auto procWorker : m_processorWorkers) {
for(const auto& procWorker : m_processorWorkers) {
result += procWorker->getProcessor().getTasksCount();
}

View File

@ -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>

View File

@ -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);
@ -180,7 +218,7 @@ bool Processor::iterate(v_int32 numIterations) {
auto CP = m_queue.first;
if (CP == nullptr) {
goto end_loop;
break;
}
if (CP->finished()) {
m_queue.popFrontNoData();
@ -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();
}
@ -217,8 +261,6 @@ bool Processor::iterate(v_int32 numIterations) {
}
end_loop:
popTasks();
std::lock_guard<oatpp::concurrency::SpinLock> lock(m_taskLock);
@ -232,6 +274,9 @@ void Processor::stop() {
m_running = false;
}
m_taskCondition.notify_one();
m_coroutineWaitListsWithTimeoutsCV.notify_one();
m_coroutineWaitListTimeoutChecker.join();
}
v_int32 Processor::getTasksCount() {

View File

@ -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.

View File

@ -39,7 +39,11 @@ namespace oatpp { namespace async { namespace worker {
void IOEventWorker::initEventQueue() {
#if !defined __ANDROID_API__ || __ANDROID_API__ >= 21
m_eventQueueHandle = ::epoll_create1(0);
#else
m_eventQueueHandle = ::epoll_create(0);
#endif
if(m_eventQueueHandle == -1) {
OATPP_LOGE("[oatpp::async::worker::IOEventWorker::initEventQueue()]", "Error. Call to ::epoll_create1() failed. errno=%d", errno);

View File

@ -31,7 +31,6 @@
#include "oatpp/core/async/Processor.hpp"
#include <unistd.h>
#include <sys/event.h>
namespace oatpp { namespace async { namespace worker {

View File

@ -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>

View File

@ -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>

View File

@ -30,15 +30,15 @@
#include <iostream>
#include <cstring>
#include <ctime>
#include <stdarg.h>
#include <cstdarg>
#if defined(WIN32) || defined(_WIN32)
#include <WinSock2.h>
#include <WinSock2.h>
struct tm* localtime_r(time_t *_clock, struct tm *_result) {
_localtime64_s(_result, _clock);
return _result;
}
struct tm* localtime_r(time_t *_clock, struct tm *_result) {
localtime_s(_result, _clock);
return _result;
}
#endif
namespace oatpp { namespace base {
@ -126,10 +126,16 @@ void DefaultLogger::log(v_uint32 priority, const std::string& tag, const std::st
}
void DefaultLogger::enablePriority(v_uint32 priority) {
if (priority > PRIORITY_E) {
return;
}
m_config.logMask |= (1 << priority);
}
void DefaultLogger::disablePriority(v_uint32 priority) {
if (priority > PRIORITY_E) {
return;
}
m_config.logMask &= ~(1 << priority);
}
@ -140,6 +146,27 @@ bool DefaultLogger::isLogPriorityEnabled(v_uint32 priority) {
return m_config.logMask & (1 << priority);
}
void LogCategory::enablePriority(v_uint32 priority) {
if (priority > Logger::PRIORITY_E) {
return;
}
enabledPriorities |= (1 << priority);
}
void LogCategory::disablePriority(v_uint32 priority) {
if (priority > Logger::PRIORITY_E) {
return;
}
enabledPriorities &= ~(1 << priority);
}
bool LogCategory::isLogPriorityEnabled(v_uint32 priority) {
if (priority > Logger::PRIORITY_E) {
return true;
}
return enabledPriorities & (1 << priority);
}
void Environment::init() {
init(std::make_shared<DefaultLogger>());
}
@ -287,13 +314,30 @@ void Environment::printCompilationConfig() {
}
void Environment::log(v_int32 priority, const std::string& tag, const std::string& message) {
void Environment::log(v_uint32 priority, const std::string& tag, const std::string& message) {
if(m_logger != nullptr) {
m_logger->log(priority, tag, message);
}
}
void Environment::logFormatted(v_int32 priority, const std::string& tag, const char* message, ...) {
void Environment::logFormatted(v_uint32 priority, const LogCategory& category, const char* message, ...) {
if (category.categoryEnabled && (category.enabledPriorities & (1 << priority))) {
va_list args;
va_start(args, message);
vlogFormatted(priority, category.tag, message, args);
va_end(args);
}
}
void Environment::logFormatted(v_uint32 priority, const std::string& tag, const char* message, ...) {
va_list args;
va_start(args, message);
vlogFormatted(priority, tag, message, args);
va_end(args);
}
void Environment::vlogFormatted(v_uint32 priority, const std::string& tag, const char* message, va_list args) {
// do we have a logger and the priority is enabled?
if (m_logger == nullptr || !m_logger->isLogPriorityEnabled(priority)) {
return;
@ -304,10 +348,9 @@ void Environment::logFormatted(v_int32 priority, const std::string& tag, const c
return;
}
// check how big our buffer has to be
va_list args;
va_start(args, message);
v_buff_size allocsize = vsnprintf(nullptr, 0, message, args) + 1;
va_end(args);
va_list argscpy;
va_copy(argscpy, args);
v_buff_size allocsize = vsnprintf(nullptr, 0, message, argscpy) + 1;
// alloc the buffer (or the max size)
if (allocsize > m_logger->getMaxFormattingBufferSize()) {
allocsize = m_logger->getMaxFormattingBufferSize();
@ -315,12 +358,9 @@ void Environment::logFormatted(v_int32 priority, const std::string& tag, const c
auto buffer = std::unique_ptr<char[]>(new char[allocsize]);
memset(buffer.get(), 0, allocsize);
// actually format
va_start(args, message);
vsnprintf(buffer.get(), allocsize, message, args);
// call (user) providen log function
log(priority, tag, buffer.get());
// cleanup
va_end(args);
}
void Environment::registerComponent(const std::string& typeName, const std::string& componentName, void* component) {

View File

@ -28,16 +28,16 @@
#include "./Config.hpp"
#include <stdio.h>
#include <cstdio>
#include <atomic>
#include <mutex>
#include <string>
#include <unordered_map>
#include <memory>
#include <stdexcept>
#include <stdlib.h>
#include <cstdlib>
#define OATPP_VERSION "1.2.0"
#define OATPP_VERSION "1.3.0"
typedef unsigned char v_char8;
typedef v_char8 *p_char8;
@ -114,6 +114,7 @@ public:
* Log priority E-error.
*/
static constexpr v_uint32 PRIORITY_E = 4;
public:
/**
* Virtual Destructor.
@ -146,6 +147,58 @@ public:
}
};
/**
* Describes a logging category (i.e. a logging "namespace")
*/
class LogCategory {
public:
/**
* Constructs a logging category.
* @param pTag - Tag of this logging category
* @param pCategoryEnabled - Enable or disable the category completely
* @param pEnabledPriorities - Bitmap of initially active logging categories.
*/
LogCategory(std::string pTag, bool pCategoryEnabled, v_uint32 pEnabledPriorities = ((1<<Logger::PRIORITY_V) | (1<<Logger::PRIORITY_D) | (1<<Logger::PRIORITY_I) | (1<<Logger::PRIORITY_W) | (1<<Logger::PRIORITY_E)))
: tag(std::move(pTag))
, categoryEnabled(pCategoryEnabled)
, enabledPriorities(pEnabledPriorities)
{};
/**
* The tag for this category
*/
const std::string tag;
/**
* Generally enable or disable this category
*/
bool categoryEnabled;
/**
* Priorities to print that are logged in this category
*/
v_uint32 enabledPriorities;
/**
* Enables logging of a priorities for this category
* @param priority - the priority level to enable
*/
void enablePriority(v_uint32 priority);
/**
* Disabled logging of a priorities for this category
* @param priority - the priority level to disable
*/
void disablePriority(v_uint32 priority);
/**
* Returns wether or not a priority of this category should be logged/printed
* @param priority
* @return - true if given priority should be logged
*/
bool isLogPriorityEnabled(v_uint32 priority);
};
/**
* Default Logger implementation.
*/
@ -301,6 +354,7 @@ public:
private:
static void registerComponent(const std::string& typeName, const std::string& componentName, void* component);
static void unregisterComponent(const std::string& typeName, const std::string& componentName);
static void vlogFormatted(v_uint32 priority, const std::string& tag, const char* message, va_list args);
public:
/**
@ -384,7 +438,7 @@ public:
* @param tag - tag of the log message.
* @param message - message.
*/
static void log(v_int32 priority, const std::string& tag, const std::string& message);
static void log(v_uint32 priority, const std::string& tag, const std::string& message);
/**
* Format message and call `Logger::log()`<br>
@ -394,7 +448,17 @@ public:
* @param message - message.
* @param ... - format arguments.
*/
static void logFormatted(v_int32 priority, const std::string& tag, const char* message, ...);
static void logFormatted(v_uint32 priority, const std::string& tag, const char* message, ...);
/**
* Format message and call `Logger::log()`<br>
* Message is formatted using `vsnprintf` method.
* @param priority - log-priority channel of the message.
* @param category - category of the log message.
* @param message - message.
* @param ... - format arguments.
*/
static void logFormatted(v_uint32 priority, const LogCategory& category, const char* message, ...);
/**
* Get component object by typeName.
@ -428,7 +492,24 @@ if(!(EXP)) { \
OATPP_LOGE("\033[1mASSERT\033[0m[\033[1;31mFAILED\033[0m]", #EXP); \
exit(EXIT_FAILURE); \
}
/**
* Convenience macro to declare a logging category directly in a class header.
* @param NAME - variable-name of the category which is later used to reference the category.
*/
#define OATPP_DECLARE_LOG_CATEGORY(NAME) \
static oatpp::base::LogCategory NAME;
/**
* Convenience macro to implement a logging category directly in a class header.
* @param NAME - variable-name of the category which is later used to reference the category.
* @param TAG - tag printed with each message printed usig this category.
* @param ENABLED - enable or disable a category (bool).
*/
#define OATPP_LOG_CATEGORY(NAME, TAG, ENABLED) \
oatpp::base::LogCategory NAME = oatpp::base::LogCategory(TAG, ENABLED);
#ifndef OATPP_DISABLE_LOGV
/**

View File

@ -1,318 +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, const void* data2, v_buff_size size) {
return std::memcmp(data1, data2, size);
}
v_buff_size StrBuffer::compare(StrBuffer* str1, StrBuffer* str2) {
if(str1 == str2) {
return 0;
}
if(str1->m_size < str2->m_size) {
return compare(str1->m_data, str2->m_data, str1->m_size);
} else {
return compare(str1->m_data, str2->m_data, str2->m_size);
}
}
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;
}
}
}}

View File

@ -1,376 +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> // c
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 data2 - pointer to data2.
* @param size - number of characters to compare.
* @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, const void* data2, v_buff_size size);
/**
* Compare data1, data2 using `std::memcmp`.
* @param data1 - data1 as `StrBuffer`.
* @param data2 - data2 as `StrBuffer`.
* @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(StrBuffer* data1, StrBuffer* data2);
/**
* 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 */

View File

@ -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 */

View File

@ -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 */

View 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;
}
}}

View 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

View File

@ -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;

View File

@ -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

View File

@ -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())

View File

@ -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);

View File

@ -86,11 +86,8 @@ void InlineWriteData::setEof() {
// ProcessingPipeline
ProcessingPipeline::ProcessingPipeline(const std::vector<base::ObjectHandle<Processor>>& processors)
: m_processors(processors)
: m_processors(processors), m_intermediateData(processors.size() - 1)
{
for(v_int32 i = 0; i < (v_int32) m_processors.size() - 1; i ++) {
m_intermediateData.push_back(data::buffer::InlineReadData());
}
}
v_io_size ProcessingPipeline::suggestInputStreamReadSize() {

View File

@ -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);
}

View File

@ -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;
}

View File

@ -87,6 +87,8 @@ namespace __class {
: notNull(pNotNull)
{}
virtual ~PolymorphicDispatcher() = default;
const bool notNull;
virtual type::Void createObject() const = 0;
@ -457,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());
}
@ -479,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());
}
@ -495,7 +497,7 @@ Void EnumInterpreterAsString<T, notnull>::fromInterpretation(const Void& interVa
try {
const auto &entry = EnumOW::getEntryByName(interValue.staticCast<String>());
return EnumOW(entry.value);
} catch (const std::runtime_error& e) { // TODO - add a specific error for this.
} catch (const std::runtime_error&) { // TODO - add a specific error for this.
error = EnumInterpreterError::ENTRY_NOT_FOUND;
}
return Void(nullptr, EnumOW::Class::getType());
@ -513,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());
}
@ -538,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());
}
@ -556,7 +558,7 @@ Void EnumInterpreterAsNumber<T, notnull>::fromInterpretation(const Void& interVa
interValue.staticCast<OW>()
);
return EnumOW(entry.value);
} catch (const std::runtime_error& e) { // TODO - add a specific error for this.
} catch (const std::runtime_error&) { // TODO - add a specific error for this.
error = EnumInterpreterError::ENTRY_NOT_FOUND;
}
return Void(nullptr, EnumOW::Class::getType());

View File

@ -51,6 +51,8 @@ namespace __class {
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;
/**

View File

@ -64,6 +64,7 @@ public:
*/
std::string description = "";
std::string pattern = "";
bool required = false;
};
private:
@ -176,6 +177,8 @@ namespace __class {
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;

View File

@ -52,6 +52,8 @@ namespace __class {
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;
/**

View File

@ -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 {

View File

@ -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<>

View File

@ -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 {};
@ -230,6 +313,9 @@ public:
*/
class AbstractInterpretation {
public:
virtual ~AbstractInterpretation() = default;
/**
* Convert the object to its interpretation.
* @param originalValue
@ -288,7 +374,7 @@ public:
Type(const ClassId& pClassId,
const char* pNameQualifier,
void* pPolymorphicDispatcher = nullptr,
InterpretationMap&& pInterpretationMap = {});
InterpretationMap&& pInterpretationMap = InterpretationMap{});
/**
* type class id.

View File

@ -51,6 +51,8 @@ namespace __class {
*/
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;

View File

@ -51,6 +51,8 @@ namespace __class {
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;
/**

View File

@ -51,6 +51,8 @@ namespace __class {
class PolymorphicDispatcher {
public:
virtual ~PolymorphicDispatcher() = default;
virtual type::Void createObject() const = 0;
/**

View File

@ -27,6 +27,8 @@
#include "./MemoryLabel.hpp"
#include "oatpp/core/concurrency/SpinLock.hpp"
#include <map>
#include <unordered_map>
namespace oatpp { namespace data { namespace share {
@ -35,22 +37,22 @@ 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<class Key>
class LazyStringMap {
template<typename Key, typename MapType>
class LazyStringMapTemplate {
public:
typedef oatpp::data::mapping::type::String String;
private:
mutable concurrency::SpinLock m_lock;
mutable bool m_fullyInitialized;
std::unordered_map<Key, StringKeyLabel> m_map;
MapType m_map;
public:
/**
* Constructor.
*/
LazyStringMap()
LazyStringMapTemplate()
: m_fullyInitialized(true)
{}
@ -58,12 +60,12 @@ public:
* Copy-constructor.
* @param other
*/
LazyStringMap(const LazyStringMap& other) {
LazyStringMapTemplate(const LazyStringMapTemplate& other) {
std::lock_guard<concurrency::SpinLock> otherLock(other.m_lock);
m_fullyInitialized = other.m_fullyInitialized;
m_map = std::unordered_map<Key, StringKeyLabel>(other.m_map);
m_map = MapType(other.m_map);
}
@ -71,7 +73,7 @@ public:
* Move constructor.
* @param other
*/
LazyStringMap(LazyStringMap&& other) {
LazyStringMapTemplate(LazyStringMapTemplate&& other) {
std::lock_guard<concurrency::SpinLock> otherLock(other.m_lock);
@ -80,7 +82,7 @@ public:
}
LazyStringMap& operator = (const LazyStringMap& other) {
LazyStringMapTemplate& operator = (const LazyStringMapTemplate& other) {
if(this != &other) {
@ -88,7 +90,7 @@ public:
std::lock_guard<concurrency::SpinLock> otherLock(other.m_lock);
m_fullyInitialized = other.m_fullyInitialized;
m_map = std::unordered_map<Key, StringKeyLabel>(other.m_map);
m_map = MapType(other.m_map);
}
@ -96,7 +98,7 @@ public:
}
LazyStringMap& operator = (LazyStringMap&& other) {
LazyStringMapTemplate& operator = (LazyStringMapTemplate&& other) {
if(this != &other) {
@ -178,6 +180,46 @@ public:
}
/**
* Erases all occurrences of key and replaces them with a new entry
* @param key
* @param value
* @return - true if an entry was replaced, false if entry was only inserted.
*/
bool putOrReplace(const Key& key, const StringKeyLabel& value) {
std::lock_guard<concurrency::SpinLock> lock(m_lock);
bool needsErase = m_map.find(key) != m_map.end();
if (needsErase) {
m_map.erase(key);
}
m_map.insert({key, value});
m_fullyInitialized = false;
return needsErase;
}
/**
* Erases all occurrences of key and replaces them with a new entry. Not thread-safe.
* @param key
* @param value
* @return - `true` if an entry was replaced, `false` if entry was only inserted.
*/
bool putOrReplace_LockFree(const Key& key, const StringKeyLabel& value) {
bool needsErase = m_map.find(key) != m_map.end();
if (needsErase) {
m_map.erase(key);
}
m_map.insert({key, value});
m_fullyInitialized = false;
return needsErase;
}
/**
* Get value as &id:oatpp::String;.
* @param key
@ -200,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
*/
@ -215,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);
@ -225,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
*/
@ -238,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);
@ -249,7 +290,7 @@ public:
* Get map of all values.
* @return
*/
const std::unordered_map<Key, StringKeyLabel>& getAll() const {
const MapType& getAll() const {
std::lock_guard<concurrency::SpinLock> lock(m_lock);
@ -271,7 +312,7 @@ public:
* Get map of all values without allocating memory for those keys/values.
* @return
*/
const std::unordered_map<Key, StringKeyLabel>& getAll_Unsafe() const {
const MapType& getAll_Unsafe() const {
return m_map;
}
@ -286,6 +327,18 @@ public:
};
/**
* Convenience template for &l:LazyStringMapTemplate;. Based on `std::unordered_map`.
*/
template<typename Key, typename Value = StringKeyLabel>
using LazyStringMap = LazyStringMapTemplate<Key, std::unordered_map<Key, Value>>;
/**
* Convenience template for &l:LazyStringMapTemplate;. Based on `std::unordered_map`.
*/
template<typename Key, typename Value = StringKeyLabel>
using LazyStringMultimap = LazyStringMapTemplate<Key, std::multimap<Key, Value>>;
}}}
#endif //oatpp_data_share_LazyStringMap_hpp

View File

@ -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())
{}
}}}

View File

@ -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,13 +217,21 @@ 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 utils::String::compare(m_data, m_size, other.m_data, other.m_size) < 0;
}
inline bool operator > (const StringKeyLabel &other) const {
return utils::String::compare(m_data, m_size, other.m_data, other.m_size) > 0;
}
};
/**
@ -226,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);
@ -239,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 {
@ -252,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 {
@ -261,69 +278,21 @@ 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);
}
};
/**
* 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 < (const StringKeyLabelCI &other) const {
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) < 0;
}
inline bool operator!=(std::nullptr_t) const {
return m_data != nullptr;
inline bool operator > (const StringKeyLabelCI &other) const {
return utils::String::compareCI_ASCII(m_data, m_size, other.m_data, other.m_size) > 0;
}
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));
}
};
}}}
@ -338,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];
@ -358,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;

View File

@ -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);
}
}

View File

@ -0,0 +1,112 @@
/***************************************************************************
*
* 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 "TemporaryFile.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/encoding/Hex.hpp"
#include "oatpp/core/utils/Random.hpp"
namespace oatpp { namespace data { namespace share {
TemporaryFile::FileHandle::~FileHandle() {
if(fileName) {
std::remove(fileName->c_str());
}
}
oatpp::String TemporaryFile::concatDirAndName(const oatpp::String& dir, const oatpp::String& filename) {
if(dir && dir->size() > 0) {
auto lastChar = dir->data()[dir->size() - 1];
if(lastChar != '/' && lastChar != '\\') {
return dir + "/" + filename;
}
return dir + filename;
}
return filename;
}
oatpp::String TemporaryFile::constructRandomFilename(const oatpp::String& dir, v_int32 randomWordSizeBytes) {
std::unique_ptr<v_char8[]> buff(new v_char8[randomWordSizeBytes]);
utils::random::Random::randomBytes(buff.get(), randomWordSizeBytes);
data::stream::BufferOutputStream s(randomWordSizeBytes * 2 + 4);
encoding::Hex::encode(&s, buff.get(), randomWordSizeBytes, encoding::Hex::ALPHABET_LOWER);
s << ".tmp";
return concatDirAndName(dir, s.toString());
}
TemporaryFile::TemporaryFile(const oatpp::String& tmpDirectory, v_int32 randomWordSizeBytes)
: m_handle(std::make_shared<FileHandle>(constructRandomFilename(tmpDirectory, randomWordSizeBytes)))
{}
TemporaryFile::TemporaryFile(const oatpp::String& tmpDirectory, const oatpp::String& tmpFileName)
: m_handle(std::make_shared<FileHandle>(concatDirAndName(tmpDirectory, tmpFileName)))
{}
oatpp::String TemporaryFile::getFullFileName() {
if(m_handle) {
return m_handle->fileName;
}
return nullptr;
}
data::stream::FileOutputStream TemporaryFile::openOutputStream() {
if(m_handle) {
return data::stream::FileOutputStream(m_handle->fileName->c_str(), "wb", m_handle);
}
throw std::runtime_error("[oatpp::data::share::TemporaryFile::openOutputStream()]: Error. FileHandle is NOT initialized.");
}
data::stream::FileInputStream TemporaryFile::openInputStream() {
if(m_handle) {
return data::stream::FileInputStream(m_handle->fileName->c_str(), m_handle);
}
throw std::runtime_error("[oatpp::data::share::TemporaryFile::openInputStream()]: Error. FileHandle is NOT initialized.");
}
std::shared_ptr<data::stream::FileOutputStream> TemporaryFile::openOutputStreamShared() {
if(m_handle) {
return std::make_shared<data::stream::FileOutputStream>(m_handle->fileName->c_str(), "wb", m_handle);
}
throw std::runtime_error("[oatpp::data::share::TemporaryFile::openOutputStreamShared()]: Error. FileHandle is NOT initialized.");
}
std::shared_ptr<data::stream::FileInputStream> TemporaryFile::openInputStreamShared() {
if(m_handle) {
return std::make_shared<data::stream::FileInputStream>(m_handle->fileName->c_str(), m_handle);
}
throw std::runtime_error("[oatpp::data::share::TemporaryFile::openInputStreamShared()]: Error. FileHandle is NOT initialized.");
}
bool TemporaryFile::moveFile(const oatpp::String& fullFileName) {
if(m_handle) {
return std::rename(m_handle->fileName->c_str(), fullFileName->c_str()) == 0;
}
return false;
}
}}}

View File

@ -0,0 +1,134 @@
/***************************************************************************
*
* 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_share_TemporaryFile_hpp
#define oatpp_data_share_TemporaryFile_hpp
#include "oatpp/core/data/stream/FileStream.hpp"
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace data { namespace share {
/**
* Temporary file - the file which gets deleted when the destructor is called
* (more precisely when all copies of the same `TemporaryFile` object deleted). <br>
* The `TemporaryFile` object internally stores a `shared_ptr` to a file handle.
* When file handle deleted it also deletes the underlying file. <br>
* Thus it's safe to copy `TemporaryFile` object and you may treat `TemporaryFile` object
* as a shared_ptr to a temporary file.
*/
class TemporaryFile {
private:
/*
* Shared handle.
* File is deleted on handle destroy.
*/
struct FileHandle {
oatpp::String fileName;
FileHandle(const oatpp::String& fullFileName)
: fileName(fullFileName)
{}
~FileHandle();
};
private:
static oatpp::String concatDirAndName(const oatpp::String& dir, const oatpp::String& filename);
static oatpp::String constructRandomFilename(const oatpp::String& dir, v_int32 randomWordSizeBytes);
private:
std::shared_ptr<FileHandle> m_handle;
public:
/**
* Default constructor.
*/
TemporaryFile() = default;
/**
* Constructor. <br>
* Create temporary file with a random name in the `tmpDirectory`. <br>
* The actual file will be created only after first write to that file. <br>
* Example of the generated random file name: `f7c6ecd44024ff31.tmp`.
* @param tmpDirectory - directory where to create a temporary file.
* @param randomWordSizeBytes - number of random bytes to generate file name.
*/
TemporaryFile(const oatpp::String& tmpDirectory, v_int32 randomWordSizeBytes = 8);
/**
* Constructor.<br>
* Create temporary file with the `tmpFileName` name in the `tmpDirectory`. <br>
* @param tmpDirectory - directory where to create a temporary file.
* @param tmpFileName - predefined name for the temporary file.
*/
TemporaryFile(const oatpp::String& tmpDirectory, const oatpp::String& tmpFileName);
/**
* Get full name of a temporary file.
* @return
*/
oatpp::String getFullFileName();
/**
* Open output stream to a temporary file. <br>
* *Note: stream also captures file-handle. The temporary file won't be deleted until the stream is deleted.*
* @return - &id:oatpp::data::stream::FileOutputStream;.
*/
data::stream::FileOutputStream openOutputStream();
/**
* Open input stream to a temporary file.
* *Note: stream also captures file-handle. The temporary file won't be deleted until the stream is deleted.*
* @return - &id:oatpp::data::stream::FileInputStream;.
*/
data::stream::FileInputStream openInputStream();
/**
* Open output stream to a temporary file. <br>
* *Note: stream also captures file-handle. The temporary file won't be deleted until the stream is deleted.*
* @return - `std::shared_ptr` to &id:oatpp::data::stream::FileOutputStream;.
*/
std::shared_ptr<data::stream::FileOutputStream> openOutputStreamShared();
/**
* Open input stream to a temporary file.
* *Note: stream also captures file-handle. The temporary file won't be deleted until the stream is deleted.*
* @return - `std::shared_ptr` &id:oatpp::data::stream::FileInputStream;.
*/
std::shared_ptr<data::stream::FileInputStream> openInputStreamShared();
/**
* Move payload to a different file. <br>
* @param fullFileName - full-file-name. Note: all the parent folders must exist.
* @return - `true` - file was successfully moved, `false` - otherwise.
*/
bool moveFile(const oatpp::String& fullFileName);
};
}}}
#endif //oatpp_data_share_TemporaryFile_hpp

View File

@ -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);
}
}
@ -147,7 +147,7 @@ oatpp::async::CoroutineStarter BufferOutputStream::flushToStreamAsync(const std:
, m_stream(stream)
{}
Action act() {
Action act() override {
if(m_inlineData.currBufferPtr == nullptr) {
m_inlineData.currBufferPtr = m_this->m_data;
m_inlineData.bytesLeft = m_this->m_position;
@ -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;
}
}}}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;

View 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);
}
}}}

View 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

View File

@ -32,14 +32,24 @@ namespace oatpp { namespace data{ namespace stream {
oatpp::data::stream::DefaultInitializedContext FileInputStream::DEFAULT_CONTEXT(data::stream::StreamType::STREAM_FINITE);
FileInputStream::FileInputStream(std::FILE* file, bool ownsFile)
FileInputStream::FileInputStream(FileInputStream&& other)
: m_file(other.m_file)
, m_ownsFile(other.m_ownsFile)
, m_ioMode(other.m_ioMode)
{
other.m_file = nullptr;
other.m_ownsFile = false;
}
FileInputStream::FileInputStream(std::FILE* file, bool ownsFile, const std::shared_ptr<void>& captureData)
: m_file(file)
, m_ownsFile(ownsFile)
, m_ioMode(IOMode::ASYNCHRONOUS)
, m_capturedData(captureData)
{}
FileInputStream::FileInputStream(const char* filename)
: FileInputStream(std::fopen(filename, "rb"), true)
FileInputStream::FileInputStream(const char* filename, const std::shared_ptr<void>& captureData)
: FileInputStream(std::fopen(filename, "rb"), true, captureData)
{
if(!m_file) {
OATPP_LOGE("[oatpp::data::stream::FileInputStream::FileInputStream(filename)]", "Error. Can't open file '%s'.", filename);
@ -48,9 +58,7 @@ FileInputStream::FileInputStream(const char* filename)
}
FileInputStream::~FileInputStream() {
if(m_ownsFile && m_file) {
std::fclose(m_file);
}
this->close();
}
std::FILE* FileInputStream::getFile() {
@ -59,7 +67,10 @@ std::FILE* FileInputStream::getFile() {
v_io_size FileInputStream::read(void *data, v_buff_size count, async::Action& action) {
(void) action;
return std::fread(data, 1, count, m_file);
if(m_file != nullptr) {
return std::fread(data, 1, count, m_file);
}
return oatpp::IOError::BROKEN_PIPE;
}
void FileInputStream::setInputStreamIOMode(IOMode ioMode) {
@ -74,19 +85,51 @@ Context& FileInputStream::getInputStreamContext() {
return DEFAULT_CONTEXT;
}
void FileInputStream::close() {
if(m_ownsFile && m_file) {
std::fclose(m_file);
}
}
FileInputStream& FileInputStream::operator=(FileInputStream&& other) {
if(this != &other) {
close();
}
m_file = other.m_file;
m_ownsFile = other.m_ownsFile;
m_ioMode = other.m_ioMode;
other.m_file = nullptr;
other.m_ownsFile = false;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FileOutputStream
oatpp::data::stream::DefaultInitializedContext FileOutputStream::DEFAULT_CONTEXT(data::stream::StreamType::STREAM_FINITE);
FileOutputStream::FileOutputStream(std::FILE* file, bool ownsFile)
FileOutputStream::FileOutputStream(FileOutputStream&& other)
: m_file(other.m_file)
, m_ownsFile(other.m_ownsFile)
, m_ioMode(other.m_ioMode)
{
other.m_file = nullptr;
other.m_ownsFile = false;
}
FileOutputStream::FileOutputStream(std::FILE* file, bool ownsFile, const std::shared_ptr<void>& captureData)
: m_file(file)
, m_ownsFile(ownsFile)
, m_ioMode(IOMode::ASYNCHRONOUS)
, m_capturedData(captureData)
{}
FileOutputStream::FileOutputStream(const char* filename, const char* mode)
: FileOutputStream(std::fopen(filename, mode), true)
FileOutputStream::FileOutputStream(const char* filename, const char* mode, const std::shared_ptr<void>& captureData)
: FileOutputStream(std::fopen(filename, mode), true, captureData)
{
if(!m_file) {
OATPP_LOGE("[oatpp::data::stream::FileOutputStream::FileOutputStream(filename, mode)]", "Error. Can't open file '%s'.", filename);
@ -95,9 +138,7 @@ FileOutputStream::FileOutputStream(const char* filename, const char* mode)
}
FileOutputStream::~FileOutputStream() {
if(m_ownsFile && m_file) {
std::fclose(m_file);
}
this->close();
}
std::FILE* FileOutputStream::getFile() {
@ -121,4 +162,26 @@ Context& FileOutputStream::getOutputStreamContext() {
return DEFAULT_CONTEXT;
}
void FileOutputStream::close() {
if(m_ownsFile && m_file) {
std::fclose(m_file);
}
}
FileOutputStream& FileOutputStream::operator=(FileOutputStream&& other) {
if(this != &other) {
close();
}
m_file = other.m_file;
m_ownsFile = other.m_ownsFile;
m_ioMode = other.m_ioMode;
other.m_file = nullptr;
other.m_ownsFile = false;
return *this;
}
}}}

View File

@ -41,20 +41,33 @@ private:
std::FILE* m_file;
bool m_ownsFile;
IOMode m_ioMode;
private:
std::shared_ptr<void> m_capturedData;
public:
FileInputStream(const FileInputStream&) = delete;
FileInputStream &operator=(const FileInputStream&) = delete;
/**
* Move constructor.
* @param other
*/
FileInputStream(FileInputStream&& other);
/**
* Constructor.
* @param file - file.
* @param ownsFile - if `true` then call close on `FileInputStream` destruction.
* @param captureData - capture auxiliary data to not get deleted until it's done with the stream.
*/
FileInputStream(std::FILE* file, bool ownsFile);
FileInputStream(std::FILE* file, bool ownsFile, const std::shared_ptr<void>& captureData = nullptr);
/**
* Constructor.
* @param filename - name of the file.
* @param captureData - capture auxiliary data to not get deleted until it's done with the stream.
*/
FileInputStream(const char* filename);
FileInputStream(const char* filename, const std::shared_ptr<void>& captureData = nullptr);
/**
* Virtual destructor.
@ -96,6 +109,13 @@ public:
*/
Context& getInputStreamContext() override;
/**
* Close file.
*/
void close();
FileInputStream& operator=(FileInputStream&& other);
};
/**
@ -108,21 +128,34 @@ private:
std::FILE* m_file;
bool m_ownsFile;
IOMode m_ioMode;
private:
std::shared_ptr<void> m_capturedData;
public:
FileOutputStream(const FileOutputStream&) = delete;
FileOutputStream &operator=(const FileOutputStream&) = delete;
/**
* Move constructor.
* @param other
*/
FileOutputStream(FileOutputStream&& other);
/**
* Constructor.
* @param file - file.
* @param ownsFile - if `true` then call close on `FileInputStream` destruction.
* @param captureData - capture auxiliary data to not get deleted until it's done with the stream.
*/
FileOutputStream(std::FILE* file, bool ownsFile);
FileOutputStream(std::FILE* file, bool ownsFile, const std::shared_ptr<void>& captureData = nullptr);
/**
* Constructor.
* @param filename - name of the file.
* @param mode - ("wb" - create new/override, "ab" - create new/append).
* @param captureData - capture auxiliary data to not get deleted until it's done with the stream.
*/
FileOutputStream(const char* filename, const char* mode = "wb");
FileOutputStream(const char* filename, const char* mode = "wb", const std::shared_ptr<void>& captureData = nullptr);
/**
* Virtual destructor.
@ -164,6 +197,13 @@ public:
*/
Context& getOutputStreamContext() override;
/**
* Close file.
*/
void close();
FileOutputStream& operator=(FileOutputStream&& other);
};
}}}

View File

@ -119,7 +119,7 @@ async::CoroutineStarter WriteCallback::writeExactSizeDataAsync(const void* data,
, m_inlineData(data, size)
{}
Action act() {
Action act() override {
return m_this->writeExactSizeDataAsyncInline(m_inlineData, finish());
}
@ -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);
}

View File

@ -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.
*/

View File

@ -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();
}
}}}

View File

@ -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.

View File

@ -24,7 +24,6 @@
#include "Caret.hpp"
#include <stdlib.h>
#include <cstdlib>
#include <algorithm>
@ -55,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];
}
@ -74,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(){
@ -130,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)
@ -142,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();
}
@ -151,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];
}
@ -174,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;
}
@ -253,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)){
@ -270,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){
@ -400,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){
@ -428,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){
@ -497,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];

View File

@ -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

View File

@ -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)

View 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

View File

@ -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.*

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}

View 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;
}
}
}}

View 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

View File

@ -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);
}
}}

View File

@ -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];

View File

@ -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.

View File

@ -24,8 +24,6 @@
#include "Unicode.hpp"
#include "./Hex.hpp"
#if defined(WIN32) || defined(_WIN32)
#include <Winsock2.h>
#else
@ -76,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;

View File

@ -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.

View File

@ -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

View File

@ -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();
}
}}

View File

@ -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)
{}

View File

@ -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 */

View 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();
}
}}

View 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

View File

@ -35,39 +35,91 @@ 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)
, m_connectionHandler(connectionHandler)
, m_threaded(false) {}
// 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()) {
auto connectionHandle = m_connectionProvider->get();
if (connectionHandle.object) {
if (getStatus() == STATUS_RUNNING) {
if (m_condition()) {
m_connectionHandler->handleConnection(connectionHandle, params /* null params */);
} else {
setStatus(STATUS_STOPPING);
}
} else {
OATPP_LOGD("[oatpp::network::server::mainLoop()]", "Error. Server already stopped - closing connection...");
}
}
} else {
setStatus(STATUS_STOPPING);
}
}
setStatus(STATUS_DONE);
}
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) {
auto connection = instance->m_connectionProvider->get();
auto connectionHandle = instance->m_connectionProvider->get();
if (connection) {
if (connectionHandle) {
if (instance->getStatus() == STATUS_RUNNING) {
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);
}
void Server::run(std::function<bool()> conditional) {
std::unique_lock<std::mutex> ul(m_mutex);
switch (getStatus()) {
case STATUS_STARTING:
throw std::runtime_error("[oatpp::network::server::run()] Error. Server already starting");
case STATUS_RUNNING:
throw std::runtime_error("[oatpp::network::server::run()] Error. Server already started");
}
m_threaded = false;
setStatus(STATUS_CREATED, STATUS_STARTING);
if (conditional) {
m_condition = std::move(conditional);
ul.unlock(); // early unlock
conditionalMainLoop();
} else {
ul.unlock();
mainLoop(this);
}
}
void Server::run(bool startAsNewThread) {
std::unique_lock<std::mutex> ul(m_mutex);
OATPP_LOGW("[oatpp::network::server::run(bool)]", "Using oatpp::network::server::run(bool) is deprecated and will be removed in the next release. Please implement your own threading (See https://github.com/oatpp/oatpp-threaded-starter).")
switch (getStatus()) {
case STATUS_STARTING:
throw std::runtime_error("[oatpp::network::server::run()] Error. Server already starting");

View File

@ -35,6 +35,7 @@
#include <atomic>
#include <thread>
#include <functional>
namespace oatpp { namespace network {
@ -46,17 +47,19 @@ class Server : public base::Countable {
private:
static void mainLoop(Server *instance);
void conditionalMainLoop();
bool setStatus(v_int32 expectedStatus, v_int32 newStatus);
void setStatus(v_int32 status);
private:
std::atomic<v_int32> m_status;
std::function<bool()> m_condition;
std::thread m_thread;
std::mutex m_mutex;
std::shared_ptr<ServerConnectionProvider> m_connectionProvider;
std::shared_ptr<ConnectionProvider> m_connectionProvider;
std::shared_ptr<ConnectionHandler> m_connectionHandler;
bool m_threaded;
@ -68,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();
@ -114,9 +117,25 @@ public:
/**
* Call &id:oatpp::network::ConnectionProvider::getConnection; in the loop and passes obtained Connection
* to &id:oatpp::network::ConnectionHandler;.
* @param startAsNewThread - Start the server blocking (thread of callee) or non-blocking (own thread)
* @param conditional - Function that is called every mainloop iteration to check if the server should continue to run <br>
* Return true to let the server continue, false to shut it down.
*/
void run(bool startAsNewThread = false);
void run(std::function<bool()> conditional = nullptr);
/**
* Call &id:oatpp::network::ConnectionProvider::getConnection; in the loop and passes obtained Connection
* to &id:oatpp::network::ConnectionHandler;.
* @param startAsNewThread - Start the server blocking (thread of callee) or non-blocking (own thread)
* @deprecated Deprecated since 1.3.0, will be removed in the next release.
* The new repository https://github.com/oatpp/oatpp-threaded-starter shows many configurations how to run Oat++ in its own thread.
* From simple No-Stop to Stop-Simple and ending in Oat++ completely isolated in its own thread-scope.
* We recommend the Stop-Simple for most applications! You can find it here: https://github.com/oatpp/oatpp-threaded-starter/blob/master/src/App_StopSimple.cpp
* The other examples are non trivial and highly specialized on specific environments or requirements.
* Please read the comments carefully and think about the consequences twice.
* If someone wants to use them please get back to us in an issue in the new repository and we can assist you with them.
* Again: These examples introduce special conditions and requirements for your code!
*/
void run(bool startAsNewThread);
/**
* Break server loop.
@ -135,10 +154,9 @@ public:
* </ul>
*/
v_int32 getStatus();
};
}}
#endif /* oatpp_network_Server_hpp */

Some files were not shown because too many files have changed in this diff Show More