mirror of
https://github.com/Expand-sys/CCash
synced 2025-12-16 16:12:14 +11:00
commit
50a0aeb0c3
73 changed files with 44770 additions and 758 deletions
|
|
@ -1,9 +1,6 @@
|
|||
/build
|
||||
/config.json
|
||||
/users.json
|
||||
/help.md
|
||||
/services.md
|
||||
/APIs.md
|
||||
/README.md
|
||||
/benchmarking.cpp
|
||||
/.github
|
||||
/benchmarking.cpp
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,4 +1,3 @@
|
|||
.vscode
|
||||
build
|
||||
config.json
|
||||
users.json
|
||||
ccash_config.hpp
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -4,3 +4,6 @@
|
|||
[submodule "drogon"]
|
||||
path = third_party/drogon
|
||||
url = https://github.com/an-tao/drogon
|
||||
[submodule "third_party/base64"]
|
||||
path = third_party/base64
|
||||
url = https://github.com/aklomp/base64
|
||||
|
|
|
|||
|
|
@ -6,25 +6,86 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra -march=native")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp )
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
src/xxhash.c
|
||||
src/bank_f.cpp
|
||||
src/bank_api.cpp
|
||||
src/bank_resp.cpp
|
||||
src/bank.cpp
|
||||
src/change_flag.cpp
|
||||
src/json_filter.cpp
|
||||
src/log.cpp
|
||||
src/simdjson.cpp
|
||||
src/str_intrusion.cpp
|
||||
src/transaction.cpp
|
||||
src/user_filter.cpp
|
||||
src/user.cpp
|
||||
src/xxhash_str.cpp
|
||||
src/xxhash.c
|
||||
|
||||
fbe/user_model/bank_dom_final_models.cpp
|
||||
fbe/user_model/bank_dom_models.cpp
|
||||
fbe/user_model/bank_dom.cpp
|
||||
fbe/user_model/fbe_final_models.cpp
|
||||
fbe/user_model/fbe_models.cpp
|
||||
fbe/user_model/fbe.cpp
|
||||
)
|
||||
|
||||
if(DEFINED USER_SAVE_LOC)
|
||||
set(USER_SAVE ${USER_SAVE_LOC})
|
||||
else()
|
||||
set(USER_SAVE "\"users.dat\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED DROGON_CONFIG_LOC)
|
||||
set(DROGON_CONFIG ${DROGON_CONFIG_LOC})
|
||||
else()
|
||||
set(DROGON_CONFIG "\"config.json\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED MAX_LOG_SIZE)
|
||||
set(MAX_LOG_SIZE_VAL ${MAX_LOG_SIZE})
|
||||
else()
|
||||
set(MAX_LOG_SIZE_VAL 100)
|
||||
endif()
|
||||
|
||||
if(DEFINED CONSERVATIVE_DISK_SAVE)
|
||||
set(CONSERVATIVE_DISK_SAVE_VAL ${CONSERVATIVE_DISK_SAVE})
|
||||
else()
|
||||
set(CONSERVATIVE_DISK_SAVE_VAL true)
|
||||
endif()
|
||||
|
||||
if(DEFINED MULTI_THREADED)
|
||||
set(MULTI_THREADED_VAL ${MULTI_THREADED})
|
||||
else()
|
||||
set(MULTI_THREADED_VAL true)
|
||||
endif()
|
||||
|
||||
if(DEFINED RETURN_ON_DEL_NAME)
|
||||
set(RETURN_ON_DEL_VAL true)
|
||||
set(RETURN_ON_DEL_NAME_VAL ${RETURN_ON_DEL_NAME})
|
||||
else()
|
||||
set(RETURN_ON_DEL_VAL false)
|
||||
set(RETURN_ON_DEL_NAME_VAL "\"\"")
|
||||
endif()
|
||||
|
||||
configure_file(ccash_config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/ccash_config.hpp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC fbe/user_model)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party/drogon/lib/inc)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party/base64/include)
|
||||
|
||||
add_subdirectory(third_party/drogon)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT} )
|
||||
|
||||
#AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/third_party/base64/lib/libbase64.o)
|
||||
|
|
|
|||
26
Dockerfile
26
Dockerfile
|
|
@ -1,16 +1,20 @@
|
|||
FROM debian:latest
|
||||
FROM alpine:3.11
|
||||
|
||||
WORKDIR /ccash
|
||||
WORKDIR /
|
||||
|
||||
RUN apt update && apt -y install build-essential g++ cmake protobuf-compiler libjsoncpp-dev uuid-dev openssl libssl-dev zlib1g-dev
|
||||
RUN apk update && apk add git cmake g++ make protobuf jsoncpp-dev openssl libressl-dev zlib-dev util-linux-dev libtool autoconf automake python3
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mkdir build
|
||||
|
||||
WORKDIR /ccash/build
|
||||
|
||||
RUN cmake ..
|
||||
RUN git clone --recurse-submodules https://github.com/EntireTwix/CCash.git --branch Refractor
|
||||
WORKDIR /CCash/third_party/base64/
|
||||
RUN AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
RUN mkdir /CCash/build
|
||||
WORKDIR /CCash/build
|
||||
RUN cmake -DDROGON_CONFIG_LOC=\"\/CCash\/config\/config.json\" -DUSER_SAVE_LOC=\"\/CCash\/config\/users.json\" ..
|
||||
RUN make -j$(nproc)
|
||||
|
||||
ENTRYPOINT ["/ccash/build/bank"]
|
||||
ARG ADMIN_A=admin
|
||||
ARG SAVE_FREQ=2
|
||||
|
||||
RUN ["chmod", "+x", "/CCash/config/ssl.sh"]
|
||||
|
||||
CMD ["sh", "-c", "/CCash/config/ssl.sh && /CCash/build/bank ${ADMIN_A} ${SAVE_FREQ}"]
|
||||
124
README.md
124
README.md
|
|
@ -1,110 +1,14 @@
|
|||
# CCash
|
||||
|
||||
A webserver hosting a bank system for Minecraft, able to be used from web browser or from CC/OC if you're playing modded.
|
||||
|
||||
the currency model most Minecraft Servers adopt if any, is resource based, usually diamonds, this model is fraught with issues however:
|
||||
|
||||
- the primary issue is minecraft worlds are infinite leading to hyper inflation as everyone accrues more diamonds
|
||||
- there is no central authority minting the currency, any consumer can introduce more diamonds to the system
|
||||
- some resources are passively reapable, making the generation of currency a larger focus then of products
|
||||
- locality is required for transaction
|
||||
- theft is possible, ownership is possession based
|
||||
|
||||
CCash solves these issues and adds a level of abstraction, the main philosophy of CCash is to have fast core operations that other services build on
|
||||
|
||||
## Build
|
||||
|
||||
drogon depedencies (varies by OS/distro)
|
||||
```
|
||||
# Debian
|
||||
sudo apt install libjsoncpp-dev uuid-dev openssl libssl-dev zlib1g-dev
|
||||
|
||||
# macOS
|
||||
brew install jsoncpp ossp-uuid openssl zlib
|
||||
```
|
||||
|
||||
building the project
|
||||
|
||||
```
|
||||
git clone --recurse-submodule https://github.com/EntireTwix/CCash/
|
||||
cd CCash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j<threads>
|
||||
```
|
||||
|
||||
then edit config.json to include the paths to your certs for HTTPS (I use certbot), or just remove the listener for port 443.
|
||||
|
||||
```
|
||||
vim ../config.json
|
||||
```
|
||||
|
||||
finally, run the program
|
||||
|
||||
```
|
||||
sudo ./bank <admin password> <saving frequency in minutes> <threads>
|
||||
```
|
||||
|
||||
## Connected Services
|
||||
|
||||
Using the Bank's API allows (you/others) to (make/use) connected services that utilize the bank, a couple ideas can be found [here](docs/services.md)
|
||||
|
||||
## Developing for
|
||||
as a dev check out
|
||||
* [APIs](https://github.com/EntireTwix/CCash/blob/main/docs/APIs.md)
|
||||
* [endpoints](https://github.com/EntireTwix/CCash/blob/main/docs/help.md)
|
||||
|
||||
## FAQ
|
||||
**Q:** how is money initially injected into the economy
|
||||
|
||||
**A:** you can take any approach you want, one that I recommend is using a one way exchange via the CC ATM above to have players mine the initial currency, this rewards early adopters and has a sunk cost effect in that the resource is promptly burned
|
||||
|
||||
## [Contributions](https://github.com/EntireTwix/CCash/graphs/contributors)
|
||||
Thank you to the contributors
|
||||
|
||||
| Name | Project Work | Connected Service Work |
|
||||
| :------------------------------------------ | ----------------------------------------------------------------------- | ---------------------- |
|
||||
| [Expand](https://github.com/Expand-sys) | Slight docker changes | Frontend |
|
||||
| [React](https://github.com/Reactified) | CC API, Logo | CC Shop, CC ATM. |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | Logs loading/adding Optimized, HTTP convention suggestions, Python API | `N/A` |
|
||||
| [Luke](https://github.com/LukeeeeBennett) | JS API, Docker, Slight Doc edits | `N/A` |
|
||||
| [Jolly](https://github.com/STBoyden) | Slight Doc edits | `N/A` |
|
||||
|
||||
## Features
|
||||
|
||||
### Performance
|
||||
- In memory database instead of on disk
|
||||
- **NOT** written in Lua, like a OC/CC implementation
|
||||
- written in **C++**, arguably the fastest language
|
||||
- **multi-threaded**
|
||||
- **parallel hashmaps** a far [superior](https://greg7mdp.github.io/parallel-hashmap/) HashMap implementation to the STD, that also benefits from multi-threaded
|
||||
- **Drogon** is a very fast [web framework](https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=composite)
|
||||
- **xxHash** for the hashing of passwords, it is very fast: [graph](https://user-images.githubusercontent.com/750081/61976089-aedeab00-af9f-11e9-9239-e5375d6c080f.png)
|
||||
- **Lightweight**, anecodotally I experienced (on my laptop's i7 6700K, 8 threads):
|
||||
- memory usage of 8.5 MB (with 0 users)
|
||||
- 0.0% CPU usage idle
|
||||
- <1% CPU on average
|
||||
- 1000 requests in parallel completed in 0.85s which spiked CPU usage to 7%
|
||||
|
||||
### Safety
|
||||
|
||||
- **Tamper Proof** relative to an in-game implementation
|
||||
- **Auto-Saving** and Saves on close
|
||||
- All passwords are **Hashed**
|
||||
- **HTTPS** (OpenSSL)
|
||||
|
||||
### Accessibility
|
||||
|
||||
- **RESTful** API for connected services like a market, gambling, or anything else you can think of
|
||||
- able to be used millions of blocks away, across dimensions, servers, **vanilla or modded**.
|
||||
- **Logging** of all transactions, configurable in [consts.hpp](include/consts.hpp)
|
||||
|
||||
### Other
|
||||
- **return balance on deletion**, configurable in [consts.hpp](include/consts.hpp)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Parallel HashMap](https://github.com/greg7mdp/parallel-hashmap/tree/master)
|
||||
- [Drogon](https://github.com/an-tao/drogon/tree/master)
|
||||
- [XXHASH](https://github.com/Cyan4973/xxHash)
|
||||
* [problem/solution](docs/idea.md)
|
||||
* connected services
|
||||
* how to contribute
|
||||
* [explanation](docs/connected_services/how_to/explanation.md)
|
||||
* [language APIs](docs/connected_services/how_to/APIs.md)
|
||||
* [API endpoints](docs/connected_services/how_to/endpoints.md)
|
||||
* [existing services](docs/connected_services/existing_services.md)
|
||||
* features
|
||||
* [user side](docs/features/user_side.md)
|
||||
* [implementation](docs/features/implementation.md)
|
||||
* [building](docs/building.md)
|
||||
* [FAQ](docs/FAQ.md)
|
||||
* [contributors](docs/contributors.md)
|
||||
* [Patreon](https://www.patreon.com/twoxx) if you wanna support this and/or future projects.
|
||||
|
|
@ -3,7 +3,9 @@
|
|||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "bank_f.h"
|
||||
#include <random>
|
||||
#include "xxhash_str.h"
|
||||
#include "bank.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -11,7 +13,6 @@
|
|||
#include <unistd.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace drogon;
|
||||
|
||||
static Bank bank;
|
||||
|
||||
|
|
@ -62,26 +63,49 @@ static Bank bank;
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bank.AddUser("twix", "root");
|
||||
bank.AddUser("jolly", "root");
|
||||
bank.admin_pass = "root";
|
||||
Op_a(bank.AddUser("", ""), "add user: ", 1000000, bank.DelUser("", ""));
|
||||
Op_a(bank.AdminAddUser("root", "", 0, ""), "admin add user: ", 1000000, bank.DelUser("", ""));
|
||||
Op(bank.SetBal("twix", "root", 1000000), "set bal: ", 1000000);
|
||||
Op(bank.SendFunds("twix", "jolly", 1, "root"), "send funds: ", 1000000);
|
||||
|
||||
bank.AddUser("", "");
|
||||
Op_a(bank.DelUser("", ""), "del user: ", 1000000, bank.AddUser("", ""));
|
||||
Op_a(bank.AdminDelUser("", "root"), "admin del user: ", 1000000, bank.AddUser("", ""));
|
||||
bank.DelUser("", "");
|
||||
bank.AddUser("twix", 0, "root");
|
||||
bank.AddUser("jolly", 0, "root");
|
||||
bank.admin_account = "twix";
|
||||
|
||||
const std::string data("this string is quite long which is relevant when testing the speed of a hasing function");
|
||||
Op(std::hash<std::string>{}(data), "hash<string>: ", 1000000);
|
||||
Op(xxHashStringGen{}(data), "xxHashStringGen: ", 1000000);
|
||||
|
||||
Op_a(bank.AddUser("abc", 0, "abc"), "add user: ", 1000000, bank.DelUser("abc"));
|
||||
Op(bank.ImpactBal("twix", 1), "impact bal: ", 1000000);
|
||||
Op(bank.SetBal("twix", 1000000), "set bal: ", 1000000);
|
||||
Op(bank.SendFunds("twix", "jolly", 1), "send funds: ", 1000000);
|
||||
Op(bank.SendFunds("", "", 1), "invalid send funds: ", 1000000);
|
||||
|
||||
bank.AddUser("abc", 0, "abc");
|
||||
Op_a(bank.DelUser("abc"), "del user: ", 1000000, bank.AddUser("abc", 0, "abc"));
|
||||
Op_a(bank.DelSelf("abc"), "del self: ", 1000000, bank.AddUser("abc", 0, "abc"));
|
||||
bank.DelUser("abc");
|
||||
|
||||
Op(bank.Contains("twix"), "contains: ", 1000000);
|
||||
Op(bank.AdminVerifyPass("root"), "admin verify pass: ", 1000000);
|
||||
Op(bank.AdminVerifyAccount("twix"), "admin verify account: ", 1000000);
|
||||
Op(bank.GetBal("twix"), "get bal: ", 1000000);
|
||||
Op(bank.VerifyPassword("twix", "root"), "verify pass: ", 1000000);
|
||||
Op(bank.ChangePassword("twix", "root", "root"), "change pass: ", 1000000);
|
||||
Op(bank.GetLogs("twix", "root"), "get logs: ", 10000);
|
||||
Op(bank.ChangePassword("twix", "root"), "change pass: ", 1000000);
|
||||
#if MAX_LOG_SIZE > 0
|
||||
Op(bank.GetLogs("twix"), "get logs: ", 1000000);
|
||||
#endif
|
||||
Op(bank.Save(), "saving: ", 1);
|
||||
|
||||
//GetBal scalining test
|
||||
//std::default_random_engine generator;
|
||||
//std::uniform_real_distribution<double> distribution(0.0, 1.0);
|
||||
|
||||
// for (size_t i = 0; i < 10000000; ++i)
|
||||
// {
|
||||
// bank.AddUser(std::to_string(i), 100000, "root");
|
||||
// if (i % 10000 == 0)
|
||||
// {
|
||||
// auto u = std::to_string((int)(distribution(generator) * i));
|
||||
// Op(bank.GetBal(u), std::to_string(i) + ", ", 100000);
|
||||
// }
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
40
ccash_config.hpp.in
Normal file
40
ccash_config.hpp.in
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
// Setting to 0 does not compile logging (useful for if disk/memory is very valuable)
|
||||
#define MAX_LOG_SIZE @MAX_LOG_SIZE_VAL@
|
||||
|
||||
//default to minecraft usernames
|
||||
constexpr unsigned min_name_size = 3;
|
||||
constexpr unsigned max_name_size = 16;
|
||||
|
||||
constexpr const char *users_location = @USER_SAVE@;
|
||||
constexpr const char *config_location = @DROGON_CONFIG@;
|
||||
|
||||
// Returns money to an account on deletion (useful if you dont want any money to leave the economy)
|
||||
#define RETURN_ON_DEL @RETURN_ON_DEL_VAL@
|
||||
constexpr const char *return_account = @RETURN_ON_DEL_NAME_VAL@;
|
||||
|
||||
/*
|
||||
if true, when frequency is hit AND changes have happened then save
|
||||
pros
|
||||
LOW disk usage
|
||||
cons
|
||||
LOW atomic overhead
|
||||
if false, when frequency is hit save
|
||||
pros
|
||||
ZERO atomic overhead
|
||||
cons
|
||||
HIGH disk usage
|
||||
*/
|
||||
#define CONSERVATIVE_DISK_SAVE @CONSERVATIVE_DISK_SAVE_VAL@
|
||||
|
||||
/*
|
||||
example, when set to 2
|
||||
version 1 will not work
|
||||
version 2 will work
|
||||
version 3 will work
|
||||
etc
|
||||
*/
|
||||
#define API_VERSION 1
|
||||
|
||||
#define MULTI_THREADED @MULTI_THREADED_VAL@
|
||||
16
config/config.json
Normal file
16
config/config.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "/CCash/config/cert.cert",
|
||||
"key": "/CCash/config/key.key"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
config/ssl.sh
Normal file
9
config/ssl.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
openssl genrsa -out server.pass.key 2048
|
||||
openssl rsa -in server.pass.key -out /CCash/config/key.key
|
||||
rm server.pass.key
|
||||
openssl req -new -key /CCash/config/key.key -out server.csr \
|
||||
-subj "/C=US/ST=CCashland/L=NEW CCASH/O=CCash/OU=Devs/CN=localhost"
|
||||
openssl x509 -req -days 365 -in server.csr -signkey /CCash/config/key.key -out /CCash/config/cert.cert
|
||||
7
config/users.json
Normal file
7
config/users.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"": {
|
||||
"balance": 0,
|
||||
"log": null,
|
||||
"password": 0
|
||||
}
|
||||
}
|
||||
1
docs/FAQ.md
Normal file
1
docs/FAQ.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
[PREVIOUS PAGE](building.md)
|
||||
136
docs/building.md
Normal file
136
docs/building.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Building
|
||||
[PREVIOUS PAGE](features/implementation.md) | [NEXT PAGE](FAQ.md)
|
||||
|
||||
## Advice
|
||||
as CCash is very lightweight it can run on practically any device but here are some tips:
|
||||
* single core machines should toggle `MULTI_THREADED` to `false`
|
||||
* if your server is sufficiently active as so that each save frequency saving is highly likely then `CONSERVATIVE_DISK_SAVE` should be toggled to `false`
|
||||
* `MAX_LOG_SIZE` should be adjusted as it takes up the most memory usage/storage of the ledger's features at ~202 bytes in memory and ~104 bytes in disk at default settings. Setting to 0 will not even compile logs
|
||||
* with no users memory usage is 8.6 Mb
|
||||
|
||||
## Drogon Depedencies
|
||||
|
||||
### Linux
|
||||
#### Debian
|
||||
```
|
||||
sudo apt install libjsoncpp-dev uuid-dev openssl libssl-dev zlib1g-dev
|
||||
```
|
||||
#### CentOS 7.5
|
||||
```
|
||||
yum install git gcc gcc-c++
|
||||
git clone https://github.com/Kitware/CMake
|
||||
cd CMake/
|
||||
./bootstrap
|
||||
make
|
||||
make install
|
||||
yum install centos-release-scl devtoolset-8
|
||||
scl enable devtoolset-8 bash
|
||||
git clone https://github.com/open-source-parsers/jsoncpp
|
||||
cd jsoncpp/
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
yum install libuuid-devel openssl-devel zlib-devel
|
||||
```
|
||||
### MacOS
|
||||
```
|
||||
brew install jsoncpp ossp-uuid openssl zlib
|
||||
```
|
||||
|
||||
### Docker
|
||||
Docker Package can be found [here](https://github.com/EntireTwix/CCash/packages/851105)
|
||||
|
||||
|
||||
## Actually, building
|
||||
```
|
||||
git clone --recurse-submodule https://github.com/EntireTwix/CCash/
|
||||
cd CCash
|
||||
cd third_party/base64
|
||||
AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
cd ../..
|
||||
mkdir build
|
||||
cd build
|
||||
mv ../config.json config.json
|
||||
```
|
||||
|
||||
### CMake Flags
|
||||
there are multiple flags responsible configuring CCash:
|
||||
| name | default | description | pros | cons |
|
||||
| :--------------------- | :--------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
|
||||
| USER_SAVE_LOC | "../users.json" | where the users are saved | `N/A` | `N/A` |
|
||||
| DROGON_CONFIG_LOC | "../config.json" | where the config is located | `N/A` | `N/A` |
|
||||
| MAX_LOG_SIZE | 100 | max number of logs per user, last `n` transactions. If both this and pre log are toggled to 0 logs will not be compiled. | large history | higher memory usage |
|
||||
| CONSERVATIVE_DISK_SAVE | `true` | when `true` only saves when changes are made | low # of disk operations | some atomic overhead |
|
||||
| MULTI_THREADED | `true` | when `true` the program is compiled to utilize `n` threads which corresponds to how many Cores your CPU has, plus 1 for saving | speed | memory lock overhead is wasteful on single core machines |
|
||||
| RETURN_ON_DEL_NAME | `N/A` | when defined, return on delete will be toggled and any accounts deleted will send their funds to the defined account, this prevent currency destruction | prevents destruction of currency | deleting accounts is made slower |
|
||||
|
||||
|
||||
EXAMPLE:
|
||||
```
|
||||
cmake ..
|
||||
```
|
||||
sets these flags to their defaults, an example of setting a flag would be
|
||||
```
|
||||
cmake -DMULTI_THREADING=false ..
|
||||
```
|
||||
with `-D`
|
||||
|
||||
### Finishing building
|
||||
lastly type in
|
||||
```
|
||||
cmake <flags of your choice or none> ..
|
||||
make -j<threads>
|
||||
./bank
|
||||
```
|
||||
|
||||
## Certs
|
||||
make sure to edit `config.json` adding the certificate location if you're using HTTPS, I personally use [certbot](https://certbot.eff.org/).
|
||||
```json
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
editing
|
||||
```json
|
||||
"cert": "pubkey",
|
||||
"key": "privkey"
|
||||
```
|
||||
|
||||
Alternatively you can delete this entire section (Disabling HTTPS in the proccess)
|
||||
```json
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
```
|
||||
leaving
|
||||
```json
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
**it is Highly recommened you secure your server**
|
||||
1
docs/connected_services/existing_services.md
Normal file
1
docs/connected_services/existing_services.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
[PREVIOUS PAGE](how_to/endpoints.md) | [NEXT PAGE](../features/user_side.md)
|
||||
8
docs/connected_services/how_to/APIs.md
Normal file
8
docs/connected_services/how_to/APIs.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
|
||||
|
||||
| language | v1 |
|
||||
| ---------------------------------------------------------------------------------------- | :----------------------: |
|
||||
| [Computer Craft](https://github.com/Reactified/rpm/blob/main/packages/ccash-api/api.lua) | :heavy_multiplication_x: |
|
||||
| [JS](https://github.com/LukeeeeBennett/ccash-client-js) | :heavy_multiplication_x: |
|
||||
| [Python](https://github.com/FearlessDoggo21/CCashPythonClient) | :heavy_multiplication_x: |
|
||||
| [Rust](https://git.stboyden.com/STBoyden/ccash-rs) | :heavy_multiplication_x: |
|
||||
BIN
docs/connected_services/how_to/connected_a.png
Normal file
BIN
docs/connected_services/how_to/connected_a.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/connected_services/how_to/connected_b.png
Normal file
BIN
docs/connected_services/how_to/connected_b.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
docs/connected_services/how_to/connected_c.png
Normal file
BIN
docs/connected_services/how_to/connected_c.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
120
docs/connected_services/how_to/endpoints.md
Normal file
120
docs/connected_services/how_to/endpoints.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# API endpoints
|
||||
[PREVIOUS PAGE](APIs.md) | [NEXT PAGE](../existing_services.md)
|
||||
|
||||
## KEY
|
||||
`Jresp` - Json Response, json must be accepted in the `Accept` header, be that via `application/json` or `*/*`, failing to do so results in error `406`
|
||||
|
||||
`Jreq` - Json Request, requires `application/json` as `content-type`, failing to do so results in error `406`
|
||||
|
||||
`U` - User, requires [basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication) in the header `Authorization`. This credential must be a valid user, failing to do so results in error `401`
|
||||
|
||||
`A` - Admin, same as `U` but in addition requires username supplied be equal to the admin account username
|
||||
|
||||
:heavy_check_mark:
|
||||
:heavy_multiplication_x:
|
||||
|
||||
## all error responses have JSON string along with them to describe
|
||||
|
||||
### Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------- | ------------------------------------------------------------------------------ | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :--------------------------------------------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| GetBal | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| GetLog | retrieves the logs of a given user, length varies by server configuration | `N/A` | api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| SendFunds | sends funds from the authenticated user to the user `{name}` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| VerifyPassword | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
|
||||
### Usage enpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------- | :----------------------: | :----------------------: | :----------------------: | :----------------: |
|
||||
| GetBal | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLog | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| VerifyPassword | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
|
||||
### Usage endpoint support
|
||||
`v` denoting the API version
|
||||
| name | v1 |
|
||||
| :------------- | :----------------: |
|
||||
| GetBal | :heavy_check_mark: |
|
||||
| GetLog | :heavy_check_mark: |
|
||||
| SendFunds | :heavy_check_mark: |
|
||||
| VerifyPassword | :heavy_check_mark: |
|
||||
|
||||
### Meta Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :---------: | :----------------------------: | :----------------: | :----------------: | :----------------------: | :----------------------: |
|
||||
| ChangePassword | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| AdminChangePassword | changes the password of a given user `{name}` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| SetBal | sets the balance of a given user `{name}` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| ImpactBal | modifies the user `{name}`'s balance by `{amount}` if positive itll add, if negative itll subtract | {"name":string,"amount":uint32} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
|
||||
### Meta Usage endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------------ | :----------------: | :----------------: | :----------------------: | :----------------: |
|
||||
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|
||||
### Meta Usage endpoint support
|
||||
| name | v1 |
|
||||
| :------------------ | :----------------: |
|
||||
| ChangePassword | :heavy_check_mark: |
|
||||
| AdminChangePassword | :heavy_check_mark: |
|
||||
| SetBal | :heavy_check_mark: |
|
||||
| ImpactBal | :heavy_check_mark: |
|
||||
|
||||
### Sytem Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :----------------- | ---------------------------------- | ---------- | ------------------------------ | :---------: | :------------: | :---------: | :----------: | :----------------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| Help | redirects to GitHub projects Docs | `N/A` | api/v1/help | `GET` | 301 | `N/A` | `N/A` | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| Close | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| Contains | checks wether a user exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| AdminVerifyAccount | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
|
||||
### System Usage endpoin errors
|
||||
| name | 401 | 404 | 406 |
|
||||
| :----------------- | :----------------------: | :----------------------: | :----------------------: |
|
||||
| Help | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| Close | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminVerifyAccount | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
|
||||
### System Usage endpoint support
|
||||
| name | v1 |
|
||||
| :----------------- | :----------------: |
|
||||
| Help | :heavy_check_mark: |
|
||||
| Close | :heavy_check_mark: |
|
||||
| Contains | :heavy_check_mark: |
|
||||
| AdminVerifyAccount | :heavy_check_mark: |
|
||||
|
||||
### Username Requirements
|
||||
Valid
|
||||
* lowercase letters
|
||||
* numbers
|
||||
* _
|
||||
* Length must be atleast 3 and at most 16 characters.
|
||||
|
||||
### User Management endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :----------- | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| AddUser | adding a user with a user of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| AdminAddUser | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| DelSelf | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| AdminDelUser | deletes a given user `{name}` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
|
||||
### User Management endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 | 409 |
|
||||
| :----------- | :----------------------: | :----------------------: | :----------------------: | :----------------: | :----------------------: |
|
||||
| AddUser | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| DelSelf | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
|
||||
### User Management endpoint support
|
||||
| name | v1 |
|
||||
| :----------- | :----------------: |
|
||||
| AddUser | :heavy_check_mark: |
|
||||
| AdminAddUser | :heavy_check_mark: |
|
||||
| DelSelf | :heavy_check_mark: |
|
||||
| AdminDelUser | :heavy_check_mark: |
|
||||
21
docs/connected_services/how_to/explanation.md
Normal file
21
docs/connected_services/how_to/explanation.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[PREVIOUS PAGE](../../idea.md) | [NEXT PAGE](APIs.md)
|
||||
|
||||
Using the ledger's API allows (you/others) to (make/use) connected services that utilize the ledger, below is a visual represenation of connected services:
|
||||
|
||||

|
||||
|
||||
ideally as the ecosystem develops, connected services become inner connected
|
||||
|
||||

|
||||
|
||||
the aim of any of these services being to provide some kind of functionality that relies on the ground truth of who has what, this information is centrally secured in CCash.
|
||||
|
||||
if you want to browse the currently available services, check out [existing_services.md](../existing_services.md)
|
||||
|
||||
to make a connected service yourself you can do so by using one of the [langauge specific APIs](APIs.md), the way they work is by providing a clean in langauge way to interface with the CCash instance
|
||||
|
||||

|
||||
|
||||
if an API does not exist for your language it is simple to make one, and I encourage you to add it to this list if you do decide to.
|
||||
|
||||
while developing make sure to reference the list of [endpoints](endpoints.md)
|
||||
9
docs/contributors.md
Normal file
9
docs/contributors.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Contributors
|
||||
| name | work |
|
||||
| :------------------------------------------ | --------------------------------------- |
|
||||
| [Luke](https://github.com/LukeeeeBennett) | Docker package, JS API |
|
||||
| [React](https://github.com/Reactified) | Logo, ComputerCraft API |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | HTTP suggestions, Python API, CCash CLI |
|
||||
| [Expand](https://github.com/Expand-sys) | Fixed docker package |
|
||||
| [Jolly](https://github.com/STBoyden) | Rust API |
|
||||
| Caesay | Restful API suggestions |
|
||||
BIN
docs/external_diagram.png
Normal file
BIN
docs/external_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
48
docs/features/implementation.md
Normal file
48
docs/features/implementation.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
[PREVIOUS PAGE](user_side.md) | [NEXT PAGE](../building.md)
|
||||
|
||||
# Implementation Features
|
||||
## [Parallel Hashmap](https://github.com/greg7mdp/parallel-hashmap)
|
||||
<!-- memory vs database -->
|
||||
<!-- and while changes arent made on the basis of speed alone it does seem to fit the problem better as we only need to save every `n` minutes/on close. -->
|
||||
<!-- phmap vs std hash map -->
|
||||
#### STD vs phmap
|
||||
this parallel hashmap implementation is the basis of CCash, its where all the user data is stored, compared to the STD's `std::unordered_map<T>` its much faster, this, multi threading support, and more can be found in the [writeup](https://greg7mdp.github.io/parallel-hashmap/).
|
||||

|
||||

|
||||
## [xxHash](https://github.com/Cyan4973/xxHash)
|
||||
xxhash is used for both hashing of passwords for storage aswell as the usernames for indexing the phmap, its speed is ridiculous at faster then `memcpy` rates of Gb/s.
|
||||
| Hash Name | Width | Bandwidth (GB/s) | Small Data Velocity | Quality | Comment |
|
||||
| --------------------- | ----- | ---------------- | ------------------- | ------- | --------------- |
|
||||
| __XXH3__ (SSE2) | 64 | 31.5 GB/s | 133.1 | 10 |
|
||||
| _RAM sequential read_ | N/A | 28.0 GB/s | N/A | N/A | _for reference_ |
|
||||
## [Base64](https://github.com/aklomp/base64)
|
||||
base64 decoding is required for Basic Auth so I used this clean and fast solution which uses SIMD.
|
||||

|
||||
## [Simdjson](https://github.com/simdjson/simdjson)
|
||||
simdjson was the fastest JSON parsing I could find, its used for request parsing.
|
||||

|
||||
## [Drogon webframework](https://github.com/an-tao/drogon)
|
||||
at the time of making this doc Drogon is the 3rd fastest web framework as per [this](https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=composite) sites metric of measuring web frameworks, it also has multi threading support.
|
||||
|
||||

|
||||
## Sparse saving
|
||||
#### Saving on close
|
||||
when the program is interupted with CONTROL + C it will save before closing the webserver, **it will not however save during a crash**.
|
||||
#### Auto Saving
|
||||
every `n` minutes, a configurable amount at launch, CCash will save.
|
||||
#### Changes
|
||||
for the above two cases, it will only save to disk if changes have been made since last save.
|
||||
#### [Binary Encoding](https://github.com/chronoxor/FastBinaryEncoding)
|
||||
saving is done using FBE, this slightly reduces file size compared to JSON and is much faster.
|
||||
| Protocol | Message size | Serialization time | Deserialization time |
|
||||
| :-------------------------------------------------------------------: | -----------: | -----------------: | -------------------: |
|
||||
| [Cap'n'Proto](https://capnproto.org) | 208 bytes | 558 ns | 359 ns |
|
||||
| [FastBinaryEncoding](https://github.com/chronoxor/FastBinaryEncoding) | 234 bytes | 66 ns | 82 ns |
|
||||
| [FlatBuffers](https://google.github.io/flatbuffers) | 280 bytes | 830 ns | 290 ns |
|
||||
| [Protobuf](https://developers.google.com/protocol-buffers) | 120 bytes | 628 ns | 759 ns |
|
||||
| [JSON](http://rapidjson.org) | 301 bytes | 740 ns | 500 ns |
|
||||
## Multi-threading support
|
||||
considering phmap and drogon both massively benefit from being multi-threaded it seemed obvious that the entire program should be, this is enabled by default and manually settable at `MULTI_THREADED`. Below are some graphs visualizing the gain of doing so:
|
||||
<!-- graph -->
|
||||
## Backwards Compatible API
|
||||
versioning is implemented by the endpoints path, for example `/v1`. Breaking changes will ideally be sparse and backwards compatability will be maintained, for example ideally API `v3` instance can still run `v1` endpoints.
|
||||
7
docs/features/user_side.md
Normal file
7
docs/features/user_side.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[PREVIOUS PAGE](../connected_services/existing_services.md) | [NEXT PAGE](implementation.md)
|
||||
|
||||
# Features
|
||||
## Performance
|
||||
## Accessibility
|
||||
## Security
|
||||
## Other
|
||||
29
docs/idea.md
Normal file
29
docs/idea.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
[PREVIOUS PAGE](../README.md) | [NEXT PAGE](connected_services/how_to/explanation.md)
|
||||
|
||||
CCash is an external ledger for in-game economies, running on a webserver with a RESTful API, exceptionally fast and lightweight written in C++.
|
||||
|
||||
While CCash can be used for anything that can interact with its API I think minecraft is a good example:
|
||||
|
||||
the currency model most Minecraft Servers adopt if any, is resource based, usually diamonds, this model is fraught with issues however:
|
||||
|
||||
* the primary issue is minecraft worlds are infinite leading to hyper inflation as everyone accrues more diamonds
|
||||
* there is no central authority minting the currency, any consumer can introduce more diamonds to the system
|
||||
* some resources are passively reapable, making the generation of currency a larger focus then of products
|
||||
* locality is required for transaction
|
||||
* theft is possible, ownership is possession based
|
||||
|
||||
CCash solves these issues and adds a level of abstraction, the main philosophy of CCash is to have fast core operations that other services build on
|
||||
|
||||
the CCash instance can be external to the game server
|
||||
|
||||

|
||||
|
||||
or on localhost:
|
||||
|
||||

|
||||
|
||||
running it local to the game server reduces latency for ComputerCraft connected services, fortunately CCash is sufficiently lightweight as to not impact performance on most setups.
|
||||
|
||||
**DISCLAIMER: if you are to run it locally and want to use ComputerCraft with it, make sure to add `127.0.0.1` to ComputerCraft's config section `allowed_domains`**
|
||||
|
||||
as CCash is just a means of keeping track of who has what, the economic system you use is self decided, ideally an admin should manage the instance to lower incentive to manipulate as they concievably already have supreme power over the given game.
|
||||
BIN
docs/localhost_diagram.png
Normal file
BIN
docs/localhost_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
27
fbe/user_model.fbe
Normal file
27
fbe/user_model.fbe
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package bank_dom
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
string from = "";
|
||||
string to = "";
|
||||
uint32 amount = 0;
|
||||
timestamp time;
|
||||
}
|
||||
|
||||
struct Logs
|
||||
{
|
||||
Transaction[] data;
|
||||
}
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32 balance = 0;
|
||||
uint64 password = 0;
|
||||
Logs? logs = null;
|
||||
}
|
||||
|
||||
struct Global
|
||||
{
|
||||
string[] keys;
|
||||
User[] users;
|
||||
}
|
||||
197
fbe/user_model/bank_dom.cpp
Normal file
197
fbe/user_model/bank_dom.cpp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
Transaction::Transaction()
|
||||
: from("")
|
||||
, to("")
|
||||
, amount((uint32_t)0ull)
|
||||
, time((uint64_t)0ull)
|
||||
{}
|
||||
|
||||
Transaction::Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time)
|
||||
: from(arg_from)
|
||||
, to(arg_to)
|
||||
, amount(arg_amount)
|
||||
, time(arg_time)
|
||||
{}
|
||||
|
||||
bool Transaction::operator==(const Transaction& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Transaction::operator<(const Transaction& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Transaction::swap(Transaction& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(from, other.from);
|
||||
swap(to, other.to);
|
||||
swap(amount, other.amount);
|
||||
swap(time, other.time);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Transaction& value)
|
||||
{
|
||||
stream << "Transaction(";
|
||||
stream << "from="; stream << "\"" << value.from << "\"";
|
||||
stream << ",to="; stream << "\"" << value.to << "\"";
|
||||
stream << ",amount="; stream << value.amount;
|
||||
stream << ",time="; stream << value.time;
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
Logs::Logs()
|
||||
: data()
|
||||
{}
|
||||
|
||||
Logs::Logs(const std::vector<::bank_dom::Transaction>& arg_data)
|
||||
: data(arg_data)
|
||||
{}
|
||||
|
||||
bool Logs::operator==(const Logs& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Logs::operator<(const Logs& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Logs::swap(Logs& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(data, other.data);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Logs& value)
|
||||
{
|
||||
stream << "Logs(";
|
||||
{
|
||||
bool first = true;
|
||||
stream << "data=[" << value.data.size() << "][";
|
||||
for (const auto& it : value.data)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << it;
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
User::User()
|
||||
: balance((uint32_t)0ull)
|
||||
, password((uint64_t)0ull)
|
||||
, logs(std::nullopt)
|
||||
{}
|
||||
|
||||
User::User(uint32_t arg_balance, uint64_t arg_password, const std::optional<::bank_dom::Logs>& arg_logs)
|
||||
: balance(arg_balance)
|
||||
, password(arg_password)
|
||||
, logs(arg_logs)
|
||||
{}
|
||||
|
||||
bool User::operator==(const User& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool User::operator<(const User& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void User::swap(User& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(balance, other.balance);
|
||||
swap(password, other.password);
|
||||
swap(logs, other.logs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const User& value)
|
||||
{
|
||||
stream << "User(";
|
||||
stream << "balance="; stream << value.balance;
|
||||
stream << ",password="; stream << value.password;
|
||||
stream << ",logs="; if (value.logs) stream << *value.logs; else stream << "null";
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
Global::Global()
|
||||
: keys()
|
||||
, users()
|
||||
{}
|
||||
|
||||
Global::Global(const std::vector<std::string>& arg_keys, const std::vector<::bank_dom::User>& arg_users)
|
||||
: keys(arg_keys)
|
||||
, users(arg_users)
|
||||
{}
|
||||
|
||||
bool Global::operator==(const Global& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Global::operator<(const Global& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Global::swap(Global& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(keys, other.keys);
|
||||
swap(users, other.users);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Global& value)
|
||||
{
|
||||
stream << "Global(";
|
||||
{
|
||||
bool first = true;
|
||||
stream << "keys=[" << value.keys.size() << "][";
|
||||
for (const auto& it : value.keys)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << "\"" << it << "\"";
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
{
|
||||
bool first = true;
|
||||
stream << ",users=[" << value.users.size() << "][";
|
||||
for (const auto& it : value.users)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << it;
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
238
fbe/user_model/bank_dom.h
Normal file
238
fbe/user_model/bank_dom.h
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace bank_dom {
|
||||
using namespace FBE;
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace FBE {
|
||||
using namespace ::bank_dom;
|
||||
} // namespace FBE
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
std::string from;
|
||||
std::string to;
|
||||
uint32_t amount;
|
||||
uint64_t time;
|
||||
|
||||
size_t fbe_type() const noexcept { return 1; }
|
||||
|
||||
Transaction();
|
||||
Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time);
|
||||
Transaction(const Transaction& other) = default;
|
||||
Transaction(Transaction&& other) = default;
|
||||
~Transaction() = default;
|
||||
|
||||
Transaction& operator=(const Transaction& other) = default;
|
||||
Transaction& operator=(Transaction&& other) = default;
|
||||
|
||||
bool operator==(const Transaction& other) const noexcept;
|
||||
bool operator!=(const Transaction& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Transaction& other) const noexcept;
|
||||
bool operator<=(const Transaction& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Transaction& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Transaction& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Transaction& value);
|
||||
|
||||
void swap(Transaction& other) noexcept;
|
||||
friend void swap(Transaction& value1, Transaction& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Transaction>
|
||||
{
|
||||
typedef bank_dom::Transaction argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Logs
|
||||
{
|
||||
std::vector<::bank_dom::Transaction> data;
|
||||
|
||||
size_t fbe_type() const noexcept { return 2; }
|
||||
|
||||
Logs();
|
||||
explicit Logs(const std::vector<::bank_dom::Transaction>& arg_data);
|
||||
Logs(const Logs& other) = default;
|
||||
Logs(Logs&& other) = default;
|
||||
~Logs() = default;
|
||||
|
||||
Logs& operator=(const Logs& other) = default;
|
||||
Logs& operator=(Logs&& other) = default;
|
||||
|
||||
bool operator==(const Logs& other) const noexcept;
|
||||
bool operator!=(const Logs& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Logs& other) const noexcept;
|
||||
bool operator<=(const Logs& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Logs& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Logs& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Logs& value);
|
||||
|
||||
void swap(Logs& other) noexcept;
|
||||
friend void swap(Logs& value1, Logs& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Logs>
|
||||
{
|
||||
typedef bank_dom::Logs argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32_t balance;
|
||||
uint64_t password;
|
||||
std::optional<::bank_dom::Logs> logs;
|
||||
|
||||
size_t fbe_type() const noexcept { return 3; }
|
||||
|
||||
User();
|
||||
User(uint32_t arg_balance, uint64_t arg_password, const std::optional<::bank_dom::Logs>& arg_logs);
|
||||
User(const User& other) = default;
|
||||
User(User&& other) = default;
|
||||
~User() = default;
|
||||
|
||||
User& operator=(const User& other) = default;
|
||||
User& operator=(User&& other) = default;
|
||||
|
||||
bool operator==(const User& other) const noexcept;
|
||||
bool operator!=(const User& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const User& other) const noexcept;
|
||||
bool operator<=(const User& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const User& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const User& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const User& value);
|
||||
|
||||
void swap(User& other) noexcept;
|
||||
friend void swap(User& value1, User& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::User>
|
||||
{
|
||||
typedef bank_dom::User argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Global
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
std::vector<::bank_dom::User> users;
|
||||
|
||||
size_t fbe_type() const noexcept { return 4; }
|
||||
|
||||
Global();
|
||||
Global(const std::vector<std::string>& arg_keys, const std::vector<::bank_dom::User>& arg_users);
|
||||
Global(const Global& other) = default;
|
||||
Global(Global&& other) = default;
|
||||
~Global() = default;
|
||||
|
||||
Global& operator=(const Global& other) = default;
|
||||
Global& operator=(Global&& other) = default;
|
||||
|
||||
bool operator==(const Global& other) const noexcept;
|
||||
bool operator!=(const Global& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Global& other) const noexcept;
|
||||
bool operator<=(const Global& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Global& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Global& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Global& value);
|
||||
|
||||
void swap(Global& other) noexcept;
|
||||
friend void swap(Global& value1, Global& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Global>
|
||||
{
|
||||
typedef bank_dom::Global argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
} // namespace bank_dom
|
||||
638
fbe/user_model/bank_dom_final_models.cpp
Normal file
638
fbe/user_model/bank_dom_final_models.cpp
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "bank_dom_final_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, from(buffer, 0)
|
||||
, to(buffer, 0)
|
||||
, amount(buffer, 0)
|
||||
, time(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ from.fbe_allocation_size(fbe_value.from)
|
||||
+ to.fbe_allocation_size(fbe_value.to)
|
||||
+ amount.fbe_allocation_size(fbe_value.amount)
|
||||
+ time.fbe_allocation_size(fbe_value.time)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::get(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.get(fbe_value.from);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.get(fbe_value.to);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.get(fbe_value.amount);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.get(fbe_value.time);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.set(fbe_value.from);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.set(fbe_value.to);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.set(fbe_value.amount);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.set(fbe_value.time);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool TransactionFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t TransactionFinalModel::serialize(const ::bank_dom::Transaction& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t TransactionFinalModel::deserialize(::bank_dom::Transaction& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::Logs>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, data(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::fbe_allocation_size(const ::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ data.fbe_allocation_size(fbe_value.data)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::get(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::get_fields(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.get(fbe_value.data);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::set(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::set_fields(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.set(fbe_value.data);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool LogsFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t LogsFinalModel::serialize(const ::bank_dom::Logs& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t LogsFinalModel::deserialize(::bank_dom::Logs& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::User>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, balance(buffer, 0)
|
||||
, password(buffer, 0)
|
||||
, logs(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::fbe_allocation_size(const ::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ balance.fbe_allocation_size(fbe_value.balance)
|
||||
+ password.fbe_allocation_size(fbe_value.password)
|
||||
+ logs.fbe_allocation_size(fbe_value.logs)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::get(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::get_fields(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.get(fbe_value.balance);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.get(fbe_value.password);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.get(fbe_value.logs);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::set(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::set_fields(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.set(fbe_value.balance);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.set(fbe_value.password);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.set(fbe_value.logs);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool UserFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t UserFinalModel::serialize(const ::bank_dom::User& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t UserFinalModel::deserialize(::bank_dom::User& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::Global>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, keys(buffer, 0)
|
||||
, users(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::fbe_allocation_size(const ::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ keys.fbe_allocation_size(fbe_value.keys)
|
||||
+ users.fbe_allocation_size(fbe_value.users)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::get(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::get_fields(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.get(fbe_value.keys);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.get(fbe_value.users);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::set(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::set_fields(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.set(fbe_value.keys);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.set(fbe_value.users);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool GlobalFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t GlobalFinalModel::serialize(const ::bank_dom::Global& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t GlobalFinalModel::deserialize(::bank_dom::Global& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
320
fbe/user_model/bank_dom_final_models.h
Normal file
320
fbe/user_model/bank_dom_final_models.h
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe_final_models.h"
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Transaction final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Transaction>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 1; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModel<std::string> from;
|
||||
FinalModel<std::string> to;
|
||||
FinalModel<uint32_t> amount;
|
||||
FinalModel<uint64_t> time;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Transaction final model
|
||||
class TransactionFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
TransactionFinalModel() : _model(this->buffer(), 8) {}
|
||||
TransactionFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Transaction>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Transaction& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Transaction& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Transaction> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Logs final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Logs>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 2; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModelVector<::bank_dom::Transaction> data;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Logs final model
|
||||
class LogsFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
LogsFinalModel() : _model(this->buffer(), 8) {}
|
||||
LogsFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Logs>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Logs& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Logs& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Logs> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::User final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::User>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 3; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::User& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::User& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::User& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModel<uint32_t> balance;
|
||||
FinalModel<uint64_t> password;
|
||||
FinalModel<std::optional<::bank_dom::Logs>> logs;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding User final model
|
||||
class UserFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
UserFinalModel() : _model(this->buffer(), 8) {}
|
||||
UserFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::User>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::User& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::User& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::User> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Global final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Global>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 4; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Global& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModelVector<std::string> keys;
|
||||
FinalModelVector<::bank_dom::User> users;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Global final model
|
||||
class GlobalFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
GlobalFinalModel() : _model(this->buffer(), 8) {}
|
||||
GlobalFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Global>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Global& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Global& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Global> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
930
fbe/user_model/bank_dom_models.cpp
Normal file
930
fbe/user_model/bank_dom_models.cpp
Normal file
|
|
@ -0,0 +1,930 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "bank_dom_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, from(buffer, 4 + 4)
|
||||
, to(buffer, from.fbe_offset() + from.fbe_size())
|
||||
, amount(buffer, to.fbe_offset() + to.fbe_size())
|
||||
, time(buffer, amount.fbe_offset() + amount.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ from.fbe_size()
|
||||
+ to.fbe_size()
|
||||
+ amount.fbe_size()
|
||||
+ time.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ from.fbe_extra()
|
||||
+ to.fbe_extra()
|
||||
+ amount.fbe_extra()
|
||||
+ time.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Transaction>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Transaction>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + from.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!from.verify())
|
||||
return false;
|
||||
fbe_current_size += from.fbe_size();
|
||||
|
||||
if ((fbe_current_size + to.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!to.verify())
|
||||
return false;
|
||||
fbe_current_size += to.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!amount.verify())
|
||||
return false;
|
||||
fbe_current_size += amount.fbe_size();
|
||||
|
||||
if ((fbe_current_size + time.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!time.verify())
|
||||
return false;
|
||||
fbe_current_size += time.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + from.fbe_size()) <= fbe_struct_size)
|
||||
from.get(fbe_value.from, "");
|
||||
else
|
||||
fbe_value.from = "";
|
||||
fbe_current_size += from.fbe_size();
|
||||
|
||||
if ((fbe_current_size + to.fbe_size()) <= fbe_struct_size)
|
||||
to.get(fbe_value.to, "");
|
||||
else
|
||||
fbe_value.to = "";
|
||||
fbe_current_size += to.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) <= fbe_struct_size)
|
||||
amount.get(fbe_value.amount, (uint32_t)0ull);
|
||||
else
|
||||
fbe_value.amount = (uint32_t)0ull;
|
||||
fbe_current_size += amount.fbe_size();
|
||||
|
||||
if ((fbe_current_size + time.fbe_size()) <= fbe_struct_size)
|
||||
time.get(fbe_value.time);
|
||||
else
|
||||
fbe_value.time = (uint64_t)0ull;
|
||||
fbe_current_size += time.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
from.set(fbe_value.from);
|
||||
to.set(fbe_value.to);
|
||||
amount.set(fbe_value.amount);
|
||||
time.set(fbe_value.time);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool TransactionModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t TransactionModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t TransactionModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t TransactionModel::serialize(const ::bank_dom::Transaction& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t TransactionModel::deserialize(::bank_dom::Transaction& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::Logs>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, data(buffer, 4 + 4)
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ data.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ data.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Logs>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Logs>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + data.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!data.verify())
|
||||
return false;
|
||||
fbe_current_size += data.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get_fields(::bank_dom::Logs& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + data.fbe_size()) <= fbe_struct_size)
|
||||
data.get(fbe_value.data);
|
||||
else
|
||||
fbe_value.data.clear();
|
||||
fbe_current_size += data.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set_fields(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
data.set(fbe_value.data);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool LogsModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t LogsModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t LogsModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t LogsModel::serialize(const ::bank_dom::Logs& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t LogsModel::deserialize(::bank_dom::Logs& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::User>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, balance(buffer, 4 + 4)
|
||||
, password(buffer, balance.fbe_offset() + balance.fbe_size())
|
||||
, logs(buffer, password.fbe_offset() + password.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ balance.fbe_size()
|
||||
+ password.fbe_size()
|
||||
+ logs.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ balance.fbe_extra()
|
||||
+ password.fbe_extra()
|
||||
+ logs.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::User>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::User>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + balance.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!balance.verify())
|
||||
return false;
|
||||
fbe_current_size += balance.fbe_size();
|
||||
|
||||
if ((fbe_current_size + password.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!password.verify())
|
||||
return false;
|
||||
fbe_current_size += password.fbe_size();
|
||||
|
||||
if ((fbe_current_size + logs.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!logs.verify())
|
||||
return false;
|
||||
fbe_current_size += logs.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get_fields(::bank_dom::User& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + balance.fbe_size()) <= fbe_struct_size)
|
||||
balance.get(fbe_value.balance, (uint32_t)0ull);
|
||||
else
|
||||
fbe_value.balance = (uint32_t)0ull;
|
||||
fbe_current_size += balance.fbe_size();
|
||||
|
||||
if ((fbe_current_size + password.fbe_size()) <= fbe_struct_size)
|
||||
password.get(fbe_value.password, (uint64_t)0ull);
|
||||
else
|
||||
fbe_value.password = (uint64_t)0ull;
|
||||
fbe_current_size += password.fbe_size();
|
||||
|
||||
if ((fbe_current_size + logs.fbe_size()) <= fbe_struct_size)
|
||||
logs.get(fbe_value.logs, std::nullopt);
|
||||
else
|
||||
fbe_value.logs = std::nullopt;
|
||||
fbe_current_size += logs.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set_fields(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
balance.set(fbe_value.balance);
|
||||
password.set(fbe_value.password);
|
||||
logs.set(fbe_value.logs);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool UserModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t UserModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t UserModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t UserModel::serialize(const ::bank_dom::User& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t UserModel::deserialize(::bank_dom::User& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::Global>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, keys(buffer, 4 + 4)
|
||||
, users(buffer, keys.fbe_offset() + keys.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ keys.fbe_size()
|
||||
+ users.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ keys.fbe_extra()
|
||||
+ users.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Global>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Global>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + keys.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!keys.verify())
|
||||
return false;
|
||||
fbe_current_size += keys.fbe_size();
|
||||
|
||||
if ((fbe_current_size + users.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!users.verify())
|
||||
return false;
|
||||
fbe_current_size += users.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get_fields(::bank_dom::Global& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + keys.fbe_size()) <= fbe_struct_size)
|
||||
keys.get(fbe_value.keys);
|
||||
else
|
||||
fbe_value.keys.clear();
|
||||
fbe_current_size += keys.fbe_size();
|
||||
|
||||
if ((fbe_current_size + users.fbe_size()) <= fbe_struct_size)
|
||||
users.get(fbe_value.users);
|
||||
else
|
||||
fbe_value.users.clear();
|
||||
fbe_current_size += users.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set_fields(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
keys.set(fbe_value.keys);
|
||||
users.set(fbe_value.users);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool GlobalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t GlobalModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t GlobalModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t GlobalModel::serialize(const ::bank_dom::Global& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t GlobalModel::deserialize(::bank_dom::Global& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
396
fbe/user_model/bank_dom_models.h
Normal file
396
fbe/user_model/bank_dom_models.h
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe_models.h"
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Transaction field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Transaction>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 1; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Transaction& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModel<std::string> from;
|
||||
FieldModel<std::string> to;
|
||||
FieldModel<uint32_t> amount;
|
||||
FieldModel<uint64_t> time;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Transaction model
|
||||
class TransactionModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
TransactionModel() : model(this->buffer(), 4) {}
|
||||
TransactionModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Transaction>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Transaction& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Transaction& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Transaction> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Logs field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Logs>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 2; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Logs& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModelVector<::bank_dom::Transaction> data;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Logs model
|
||||
class LogsModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
LogsModel() : model(this->buffer(), 4) {}
|
||||
LogsModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Logs>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Logs& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Logs& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Logs> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::User field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::User>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 3; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::User& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::User& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::User& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModel<uint32_t> balance;
|
||||
FieldModel<uint64_t> password;
|
||||
FieldModel<std::optional<::bank_dom::Logs>> logs;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding User model
|
||||
class UserModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
UserModel() : model(this->buffer(), 4) {}
|
||||
UserModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::User>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::User& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::User& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::User> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Global field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Global>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 4; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Global& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModelVector<std::string> keys;
|
||||
FieldModelVector<::bank_dom::User> users;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Global model
|
||||
class GlobalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
GlobalModel() : model(this->buffer(), 4) {}
|
||||
GlobalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Global>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Global& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Global& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Global> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
401
fbe/user_model/fbe.cpp
Normal file
401
fbe/user_model/fbe.cpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
std::string buffer_t::base64encode() const
|
||||
{
|
||||
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
std::string result;
|
||||
|
||||
int val = 0;
|
||||
int valb = -6;
|
||||
for (auto c : _data)
|
||||
{
|
||||
val = (val << 8) + c;
|
||||
valb += 8;
|
||||
while (valb >= 0)
|
||||
{
|
||||
result.push_back(base64[(val >> valb) & 0x3F]);
|
||||
valb -= 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (valb > -6)
|
||||
result.push_back(base64[((val << 8) >> (valb + 8)) & 0x3F]);
|
||||
|
||||
while (result.size() % 4)
|
||||
result.push_back('=');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
buffer_t buffer_t::base64decode(const std::string& str)
|
||||
{
|
||||
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
buffer_t result;
|
||||
|
||||
std::vector<int> pattern(256, -1);
|
||||
for (int i = 0; i < 64; ++i)
|
||||
pattern[base64[i]] = i;
|
||||
|
||||
int val = 0;
|
||||
int valb = -8;
|
||||
for (auto c : str)
|
||||
{
|
||||
if (pattern[c] == -1)
|
||||
break;
|
||||
|
||||
val = (val << 6) + pattern[c];
|
||||
valb += 6;
|
||||
|
||||
if (valb >= 0)
|
||||
{
|
||||
result.push_back((uint8_t)((val >> valb) & 0xFF));
|
||||
valb -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t utc()
|
||||
{
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
struct timespec timestamp;
|
||||
if (clock_gettime(CLOCK_REALTIME, ×tamp) != 0)
|
||||
throw std::runtime_error("Cannot get value of CLOCK_REALTIME timer!");
|
||||
return (timestamp.tv_sec * 1000000000) + timestamp.tv_nsec;
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
FILETIME ft;
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
|
||||
ULARGE_INTEGER result;
|
||||
result.LowPart = ft.dwLowDateTime;
|
||||
result.HighPart = ft.dwHighDateTime;
|
||||
return (result.QuadPart - 116444736000000000ull) * 100;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t unhex(char ch)
|
||||
{
|
||||
if ((ch >= '0') && (ch <= '9'))
|
||||
return ch - '0';
|
||||
else if ((ch >= 'a') && (ch <= 'f'))
|
||||
return 10 + ch - 'a';
|
||||
else if ((ch >= 'A') && (ch <= 'F'))
|
||||
return 10 + ch - 'A';
|
||||
else
|
||||
return 255;
|
||||
}
|
||||
|
||||
uuid_t::uuid_t(const std::string& uuid)
|
||||
{
|
||||
char v1 = 0;
|
||||
char v2 = 0;
|
||||
bool pack = false;
|
||||
size_t index = 0;
|
||||
|
||||
// Parse UUID string
|
||||
for (auto ch : uuid)
|
||||
{
|
||||
if ((ch == '-') || (ch == '{') || (ch == '}'))
|
||||
continue;
|
||||
|
||||
if (pack)
|
||||
{
|
||||
v2 = ch;
|
||||
pack = false;
|
||||
uint8_t ui1 = unhex(v1);
|
||||
uint8_t ui2 = unhex(v2);
|
||||
if ((ui1 > 15) || (ui2 > 15))
|
||||
throw std::invalid_argument("Invalid UUID string: " + uuid);
|
||||
_data[index++] = ui1 * 16 + ui2;
|
||||
if (index >= 16)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = ch;
|
||||
pack = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill remaining data with zeros
|
||||
for (; index < 16; ++index)
|
||||
_data[index++] = 0;
|
||||
}
|
||||
|
||||
std::string uuid_t::string() const
|
||||
{
|
||||
const char* digits = "0123456789abcdef";
|
||||
|
||||
std::string result(36, '0');
|
||||
|
||||
int index = 0;
|
||||
for (auto value : _data)
|
||||
{
|
||||
result[index++] = digits[(value >> 4) & 0x0F];
|
||||
result[index++] = digits[(value >> 0) & 0x0F];
|
||||
if ((index == 8) || (index == 13) || (index == 18) || (index == 23))
|
||||
result[index++] = '-';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uuid_t uuid_t::sequential()
|
||||
{
|
||||
uuid_t result;
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
::uuid_t uuid;
|
||||
uuid_generate_time(uuid);
|
||||
result._data[0] = uuid[0];
|
||||
result._data[1] = uuid[1];
|
||||
result._data[2] = uuid[2];
|
||||
result._data[3] = uuid[3];
|
||||
result._data[4] = uuid[4];
|
||||
result._data[5] = uuid[5];
|
||||
result._data[6] = uuid[6];
|
||||
result._data[7] = uuid[7];
|
||||
result._data[8] = uuid[8];
|
||||
result._data[9] = uuid[9];
|
||||
result._data[10] = uuid[10];
|
||||
result._data[11] = uuid[11];
|
||||
result._data[12] = uuid[12];
|
||||
result._data[13] = uuid[13];
|
||||
result._data[14] = uuid[14];
|
||||
result._data[15] = uuid[15];
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
::UUID uuid;
|
||||
if (UuidCreateSequential(&uuid) != RPC_S_OK)
|
||||
throw std::runtime_error("Cannot generate sequential UUID!");
|
||||
|
||||
result._data[0] = (uuid.Data1 >> 24) & 0xFF;
|
||||
result._data[1] = (uuid.Data1 >> 16) & 0xFF;
|
||||
result._data[2] = (uuid.Data1 >> 8) & 0xFF;
|
||||
result._data[3] = (uuid.Data1 >> 0) & 0xFF;
|
||||
result._data[4] = (uuid.Data2 >> 8) & 0xFF;
|
||||
result._data[5] = (uuid.Data2 >> 0) & 0xFF;
|
||||
|
||||
result._data[6] = (uuid.Data3 >> 8) & 0xFF;
|
||||
result._data[7] = (uuid.Data3 >> 0) & 0xFF;
|
||||
|
||||
result._data[8] = uuid.Data4[0];
|
||||
result._data[9] = uuid.Data4[1];
|
||||
|
||||
result._data[10] = uuid.Data4[2];
|
||||
result._data[11] = uuid.Data4[3];
|
||||
result._data[12] = uuid.Data4[4];
|
||||
result._data[13] = uuid.Data4[5];
|
||||
result._data[14] = uuid.Data4[6];
|
||||
result._data[15] = uuid.Data4[7];
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
uuid_t uuid_t::random()
|
||||
{
|
||||
uuid_t result;
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
::uuid_t uuid;
|
||||
uuid_generate_random(uuid);
|
||||
result._data[0] = uuid[0];
|
||||
result._data[1] = uuid[1];
|
||||
result._data[2] = uuid[2];
|
||||
result._data[3] = uuid[3];
|
||||
result._data[4] = uuid[4];
|
||||
result._data[5] = uuid[5];
|
||||
result._data[6] = uuid[6];
|
||||
result._data[7] = uuid[7];
|
||||
result._data[8] = uuid[8];
|
||||
result._data[9] = uuid[9];
|
||||
result._data[10] = uuid[10];
|
||||
result._data[11] = uuid[11];
|
||||
result._data[12] = uuid[12];
|
||||
result._data[13] = uuid[13];
|
||||
result._data[14] = uuid[14];
|
||||
result._data[15] = uuid[15];
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
::UUID uuid;
|
||||
if (UuidCreate(&uuid) != RPC_S_OK)
|
||||
throw std::runtime_error("Cannot generate random UUID!");
|
||||
|
||||
result._data[0] = (uuid.Data1 >> 24) & 0xFF;
|
||||
result._data[1] = (uuid.Data1 >> 16) & 0xFF;
|
||||
result._data[2] = (uuid.Data1 >> 8) & 0xFF;
|
||||
result._data[3] = (uuid.Data1 >> 0) & 0xFF;
|
||||
result._data[4] = (uuid.Data2 >> 8) & 0xFF;
|
||||
result._data[5] = (uuid.Data2 >> 0) & 0xFF;
|
||||
|
||||
result._data[6] = (uuid.Data3 >> 8) & 0xFF;
|
||||
result._data[7] = (uuid.Data3 >> 0) & 0xFF;
|
||||
|
||||
result._data[8] = uuid.Data4[0];
|
||||
result._data[9] = uuid.Data4[1];
|
||||
|
||||
result._data[10] = uuid.Data4[2];
|
||||
result._data[11] = uuid.Data4[3];
|
||||
result._data[12] = uuid.Data4[4];
|
||||
result._data[13] = uuid.Data4[5];
|
||||
result._data[14] = uuid.Data4[6];
|
||||
result._data[15] = uuid.Data4[7];
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
CppLogging::Record& operator<<(CppLogging::Record& record, const uuid_t& uuid)
|
||||
{
|
||||
const char* digits = "0123456789abcdef";
|
||||
|
||||
std::array<char, 36> result;
|
||||
|
||||
int index = 0;
|
||||
for (auto value : uuid.data())
|
||||
{
|
||||
result[index++] = digits[(value >> 4) & 0x0F];
|
||||
result[index++] = digits[(value >> 0) & 0x0F];
|
||||
if ((index == 8) || (index == 13) || (index == 18) || (index == 23))
|
||||
result[index++] = '-';
|
||||
}
|
||||
|
||||
return record.StoreCustom(std::string_view(result.data(), result.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
void FBEBuffer::attach(const void* data, size_t size, size_t offset)
|
||||
{
|
||||
assert((data != nullptr) && "Invalid buffer!");
|
||||
if (data == nullptr)
|
||||
throw std::invalid_argument("Invalid buffer!");
|
||||
assert((size > 0) && "Invalid size!");
|
||||
if (size == 0)
|
||||
throw std::invalid_argument("Invalid size!");
|
||||
assert((offset <= size) && "Invalid offset!");
|
||||
if (offset > size)
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
_data = (uint8_t*)data;
|
||||
_capacity = 0;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::attach(const std::vector<uint8_t>& buffer, size_t offset)
|
||||
{
|
||||
assert((buffer.data() != nullptr) && "Invalid buffer!");
|
||||
if (buffer.data() == nullptr)
|
||||
throw std::invalid_argument("Invalid buffer!");
|
||||
assert((buffer.size() > 0) && "Invalid size!");
|
||||
if (buffer.size() == 0)
|
||||
throw std::invalid_argument("Invalid size!");
|
||||
assert((offset <= buffer.size()) && "Invalid offset!");
|
||||
if (offset > buffer.size())
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
_data = (uint8_t*)buffer.data();
|
||||
_capacity = 0;
|
||||
_size = buffer.size();
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::clone(const void* data, size_t size, size_t offset)
|
||||
{
|
||||
assert((offset <= size) && "Invalid offset!");
|
||||
if (offset > size)
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
reserve(size);
|
||||
std::memcpy(_data, data, size);
|
||||
_capacity = size;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::clone(const std::vector<uint8_t>& buffer, size_t offset)
|
||||
{
|
||||
assert((offset <= buffer.size()) && "Invalid offset!");
|
||||
if (offset > buffer.size())
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
size_t size = buffer.size();
|
||||
|
||||
reserve(size);
|
||||
std::memcpy(_data, buffer.data(), size);
|
||||
_capacity = size;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
size_t FBEBuffer::allocate(size_t size)
|
||||
{
|
||||
size_t offset = _size;
|
||||
|
||||
// Calculate a new buffer size
|
||||
size_t total = _size + size;
|
||||
|
||||
if (total <= _capacity)
|
||||
{
|
||||
_size = total;
|
||||
return offset;
|
||||
}
|
||||
|
||||
_capacity = std::max(total, 2 * _capacity);
|
||||
uint8_t* data = (uint8_t*)std::malloc(_capacity);
|
||||
std::memcpy(data, _data, _size);
|
||||
std::free(_data);
|
||||
_data = data;
|
||||
_size = total;
|
||||
return offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::remove(size_t offset, size_t size)
|
||||
{
|
||||
assert(((offset + size) <= _size) && "Invalid offset & size!");
|
||||
if ((offset + size) > _size)
|
||||
throw std::invalid_argument("Invalid offset & size!");
|
||||
|
||||
std::memcpy(_data + offset, _data + offset + size, _size - size - offset);
|
||||
_size -= size;
|
||||
if (_offset >= (offset + size))
|
||||
_offset -= size;
|
||||
else if (_offset >= offset)
|
||||
{
|
||||
_offset -= _offset - offset;
|
||||
if (_offset > _size)
|
||||
_offset = _size;
|
||||
}
|
||||
}
|
||||
|
||||
void FBEBuffer::reserve(size_t capacity)
|
||||
{
|
||||
if (capacity > _capacity)
|
||||
{
|
||||
_capacity = std::max(capacity, 2 * _capacity);
|
||||
uint8_t* data = (uint8_t*)std::malloc(_capacity);
|
||||
std::memcpy(data, _data, _size);
|
||||
std::free(_data);
|
||||
_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
void FBEBuffer::resize(size_t size)
|
||||
{
|
||||
reserve(size);
|
||||
_size = size;
|
||||
if (_offset > _size)
|
||||
_offset = _size;
|
||||
}
|
||||
|
||||
void FBEBuffer::reset()
|
||||
{
|
||||
_size = 0;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
650
fbe/user_model/fbe.h
Normal file
650
fbe/user_model/fbe.h
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
#include <time.h>
|
||||
#include <uuid/uuid.h>
|
||||
#undef HOST_NOT_FOUND
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#undef DELETE
|
||||
#undef ERROR
|
||||
#undef HOST_NOT_FOUND
|
||||
#undef Yield
|
||||
#undef min
|
||||
#undef max
|
||||
#undef uuid_t
|
||||
#endif
|
||||
|
||||
namespace FBE {
|
||||
|
||||
//! Bytes buffer type
|
||||
/*!
|
||||
Represents bytes buffer which is a lightweight wrapper around std::vector<uint8_t>
|
||||
with similar interface.
|
||||
*/
|
||||
class buffer_t
|
||||
{
|
||||
public:
|
||||
typedef std::vector<uint8_t>::iterator iterator;
|
||||
typedef std::vector<uint8_t>::const_iterator const_iterator;
|
||||
typedef std::vector<uint8_t>::reverse_iterator reverse_iterator;
|
||||
typedef std::vector<uint8_t>::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
buffer_t() = default;
|
||||
buffer_t(size_t capacity) { reserve(capacity); }
|
||||
buffer_t(const std::string& str) { assign(str); }
|
||||
buffer_t(size_t size, uint8_t value) { assign(size, value); }
|
||||
buffer_t(const uint8_t* data, size_t size) { assign(data, size); }
|
||||
buffer_t(const std::vector<uint8_t>& other) : _data(other) {}
|
||||
buffer_t(std::vector<uint8_t>&& other) : _data(std::move(other)) {}
|
||||
buffer_t(const buffer_t& other) = default;
|
||||
buffer_t(buffer_t&& other) = default;
|
||||
~buffer_t() = default;
|
||||
|
||||
buffer_t& operator=(const std::string& str) { assign(str); return *this; }
|
||||
buffer_t& operator=(const std::vector<uint8_t>& other) { _data = other; return *this; }
|
||||
buffer_t& operator=(std::vector<uint8_t>&& other) { _data = std::move(other); return *this; }
|
||||
buffer_t& operator=(const buffer_t& other) = default;
|
||||
buffer_t& operator=(buffer_t&& other) = default;
|
||||
|
||||
uint8_t& operator[](size_t index) { return _data[index]; }
|
||||
const uint8_t& operator[](size_t index) const { return _data[index]; }
|
||||
|
||||
bool empty() const { return _data.empty(); }
|
||||
size_t capacity() const { return _data.capacity(); }
|
||||
size_t size() const { return _data.size(); }
|
||||
size_t max_size() const { return _data.max_size(); }
|
||||
|
||||
std::vector<uint8_t>& buffer() noexcept { return _data; }
|
||||
const std::vector<uint8_t>& buffer() const noexcept { return _data; }
|
||||
uint8_t* data() noexcept { return _data.data(); }
|
||||
const uint8_t* data() const noexcept { return _data.data(); }
|
||||
uint8_t& at(size_t index) { return _data.at(index); }
|
||||
const uint8_t& at(size_t index) const { return _data.at(index); }
|
||||
uint8_t& front() { return _data.front(); }
|
||||
const uint8_t& front() const { return _data.front(); }
|
||||
uint8_t& back() { return _data.back(); }
|
||||
const uint8_t& back() const { return _data.back(); }
|
||||
|
||||
void reserve(size_t capacity) { _data.reserve(capacity); }
|
||||
void resize(size_t size, uint8_t value = 0) { _data.resize(size, value); }
|
||||
void shrink_to_fit() { _data.shrink_to_fit(); }
|
||||
|
||||
void assign(const std::string& str) { assign((const uint8_t*)str.c_str(), str.size()); }
|
||||
void assign(const std::vector<uint8_t>& vec) { assign(vec.begin(), vec.end()); }
|
||||
void assign(size_t size, uint8_t value) { _data.assign(size, value); }
|
||||
void assign(const uint8_t* data, size_t size) { _data.assign(data, data + size); }
|
||||
template <class InputIterator>
|
||||
void assign(InputIterator first, InputIterator last) { _data.assign(first, last); }
|
||||
iterator insert(const_iterator position, uint8_t value) { return _data.insert(position, value); }
|
||||
iterator insert(const_iterator position, const std::string& str) { return insert(position, (const uint8_t*)str.c_str(), str.size()); }
|
||||
iterator insert(const_iterator position, const std::vector<uint8_t>& vec) { return insert(position, vec.begin(), vec.end()); }
|
||||
iterator insert(const_iterator position, size_t size, uint8_t value) { return _data.insert(position, size, value); }
|
||||
iterator insert(const_iterator position, const uint8_t* data, size_t size) { return _data.insert(position, data, data + size); }
|
||||
template <class InputIterator>
|
||||
iterator insert(const_iterator position, InputIterator first, InputIterator last) { return _data.insert(position, first, last); }
|
||||
iterator erase(const_iterator position) { return _data.erase(position); }
|
||||
iterator erase(const_iterator first, const_iterator last) { return _data.erase(first, last); }
|
||||
void clear() noexcept { _data.clear(); }
|
||||
|
||||
void push_back(uint8_t value) { _data.push_back(value); }
|
||||
void pop_back() { _data.pop_back(); }
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator position, Args&&... args) { return _data.emplace(position, args...); }
|
||||
template <class... Args>
|
||||
void emplace_back(Args&&... args) { _data.emplace_back(args...); }
|
||||
|
||||
iterator begin() noexcept { return _data.begin(); }
|
||||
const_iterator begin() const noexcept { return _data.begin(); }
|
||||
const_iterator cbegin() const noexcept { return _data.cbegin(); }
|
||||
reverse_iterator rbegin() noexcept { return _data.rbegin(); }
|
||||
const_reverse_iterator rbegin() const noexcept { return _data.rbegin(); }
|
||||
const_reverse_iterator crbegin() const noexcept { return _data.crbegin(); }
|
||||
iterator end() noexcept { return _data.end(); }
|
||||
const_iterator end() const noexcept { return _data.end(); }
|
||||
const_iterator cend() const noexcept { return _data.cend(); }
|
||||
reverse_iterator rend() noexcept { return _data.rend(); }
|
||||
const_reverse_iterator rend() const noexcept { return _data.rend(); }
|
||||
const_reverse_iterator crend() const noexcept { return _data.crend(); }
|
||||
|
||||
//! Get the string equivalent from the bytes buffer
|
||||
std::string string() const { return std::string(_data.begin(), _data.end()); }
|
||||
|
||||
//! Encode the Base64 string from the bytes buffer
|
||||
std::string base64encode() const;
|
||||
//! Decode the bytes buffer from the Base64 string
|
||||
static buffer_t base64decode(const std::string& str);
|
||||
|
||||
//! Swap two instances
|
||||
void swap(buffer_t& value) noexcept
|
||||
{ using std::swap; swap(_data, value._data); }
|
||||
friend void swap(buffer_t& value1, buffer_t& value2) noexcept
|
||||
{ value1.swap(value2); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
|
||||
//! Decimal type
|
||||
/*!
|
||||
Represents decimal type using double and provides basic arithmetic operations.
|
||||
*/
|
||||
class decimal_t
|
||||
{
|
||||
public:
|
||||
decimal_t() noexcept { _value = 0.0; }
|
||||
decimal_t(int8_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint8_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int16_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint16_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int32_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint32_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int64_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint64_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(float value) noexcept { _value = (double)value; }
|
||||
decimal_t(double value) noexcept { _value = value; }
|
||||
template <typename T>
|
||||
explicit decimal_t(const T& value) noexcept { _value = (double)value; }
|
||||
decimal_t(const decimal_t& value) noexcept = default;
|
||||
decimal_t(decimal_t&& value) noexcept = default;
|
||||
~decimal_t() noexcept = default;
|
||||
|
||||
template <typename T>
|
||||
decimal_t& operator=(const T& value) noexcept { _value = (double)value; return *this; }
|
||||
decimal_t& operator=(const decimal_t& value) noexcept = default;
|
||||
decimal_t& operator=(decimal_t&& value) noexcept = default;
|
||||
|
||||
// Arithmetic operators
|
||||
decimal_t operator+() const noexcept { return decimal_t(_value); }
|
||||
decimal_t operator-() const noexcept { return decimal_t(-_value); }
|
||||
|
||||
decimal_t& operator++() noexcept { return *this += 1; }
|
||||
decimal_t operator++(int) noexcept { decimal_t temp(*this); ++*this; return temp; }
|
||||
decimal_t& operator--() noexcept { return *this -= 1; }
|
||||
decimal_t operator--(int) noexcept { decimal_t temp(*this); --*this; return temp; }
|
||||
|
||||
decimal_t& operator+=(const decimal_t& value) noexcept { return *this = *this + value; }
|
||||
decimal_t& operator-=(const decimal_t& value) noexcept { return *this = *this - value; }
|
||||
decimal_t& operator*=(const decimal_t& value) noexcept { return *this = *this * value; }
|
||||
decimal_t& operator/=(const decimal_t& value) { return *this = *this / value; }
|
||||
|
||||
template <typename T>
|
||||
decimal_t& operator+=(const T& value) noexcept { return *this = *this + decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator-=(const T& value) noexcept { return *this = *this - decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator*=(const T& value) noexcept { return *this = *this * decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator/=(const T& value) { return *this = *this / decimal_t(value); }
|
||||
|
||||
template <typename T>
|
||||
friend T& operator+=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) + value2); }
|
||||
template <typename T>
|
||||
friend T& operator-=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) - value2); }
|
||||
template <typename T>
|
||||
friend T& operator*=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) * value2); }
|
||||
template <typename T>
|
||||
friend T& operator/=(T& value1, const decimal_t& value2) { return value1 = (T)(decimal_t(value1) / value2); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator+(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) + value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator+(const decimal_t& value1, const T& value2) noexcept { return value1 + decimal_t(value2); }
|
||||
friend decimal_t operator+(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value + value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator-(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) - value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator-(const decimal_t& value1, const T& value2) noexcept { return value1 - decimal_t(value2); }
|
||||
friend decimal_t operator-(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value - value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator*(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) * value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator*(const decimal_t& value1, const T& value2) noexcept { return value1 * decimal_t(value2); }
|
||||
friend decimal_t operator*(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value * value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator/(const T& value1, const decimal_t& value2) { return decimal_t(value1) / value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator/(const decimal_t& value1, const T& value2) { return value1 / decimal_t(value2); }
|
||||
friend decimal_t operator/(const decimal_t& value1, const decimal_t& value2) { return decimal_t(value1._value / value2._value); }
|
||||
|
||||
// Comparison operators
|
||||
template <typename T>
|
||||
friend bool operator==(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) == value2; }
|
||||
template <typename T>
|
||||
friend bool operator==(const decimal_t& value1, const T& value2) noexcept { return value1 == decimal_t(value2); }
|
||||
friend bool operator==(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value == value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator!=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) != value2; }
|
||||
template <typename T>
|
||||
friend bool operator!=(const decimal_t& value1, const T& value2) noexcept { return value1 != decimal_t(value2); }
|
||||
friend bool operator!=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value != value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator<(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) < value2; }
|
||||
template <typename T>
|
||||
friend bool operator<(const decimal_t& value1, const T& value2) noexcept { return value1 < decimal_t(value2); }
|
||||
friend bool operator<(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value < value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator>(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) > value2; }
|
||||
template <typename T>
|
||||
friend bool operator>(const decimal_t& value1, const T& value2) noexcept { return value1 > decimal_t(value2); }
|
||||
friend bool operator>(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value > value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator<=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) <= value2; }
|
||||
template <typename T>
|
||||
friend bool operator<=(const decimal_t& value1, const T& value2) noexcept { return value1 <= decimal_t(value2); }
|
||||
friend bool operator<=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value <= value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator>=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) >= value2; }
|
||||
template <typename T>
|
||||
friend bool operator>=(const decimal_t& value1, const T& value2) noexcept { return value1 >= decimal_t(value2); }
|
||||
friend bool operator>=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value >= value2._value; }
|
||||
|
||||
// Type cast
|
||||
operator bool() const noexcept { return (_value != 0.0); }
|
||||
operator uint8_t() const noexcept { return (uint8_t)_value; }
|
||||
operator uint16_t() const noexcept { return (uint16_t)_value; }
|
||||
operator uint32_t() const noexcept { return (uint32_t)_value; }
|
||||
operator uint64_t() const noexcept { return (uint64_t)_value; }
|
||||
operator float() const noexcept { return (float)_value; }
|
||||
operator double() const noexcept { return (double)_value; }
|
||||
|
||||
//! Get string from the current decimal value
|
||||
std::string string() const { return std::to_string(_value); }
|
||||
|
||||
//! Input instance from the given input stream
|
||||
friend std::istream& operator>>(std::istream& is, decimal_t& value)
|
||||
{ is >> value._value; return is; }
|
||||
//! Output instance into the given output stream
|
||||
friend std::ostream& operator<<(std::ostream& os, const decimal_t& value)
|
||||
{ os << value.string(); return os; }
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
//! Store logging format
|
||||
friend CppLogging::Record& operator<<(CppLogging::Record& record, const decimal_t& value)
|
||||
{ return record.StoreCustom(value._value); }
|
||||
#endif
|
||||
|
||||
//! Swap two instances
|
||||
void swap(decimal_t& value) noexcept
|
||||
{ using std::swap; swap(_value, value._value); }
|
||||
friend void swap(decimal_t& value1, decimal_t& value2) noexcept
|
||||
{ value1.swap(value2); }
|
||||
|
||||
private:
|
||||
double _value;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<FBE::decimal_t>
|
||||
{
|
||||
typedef FBE::decimal_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
result = result * 31 + std::hash<double>()((double)value);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Register a new enum-based flags macro
|
||||
#define FBE_ENUM_FLAGS(type)\
|
||||
inline FBE::Flags<type> operator|(type f1, type f2) noexcept { return FBE::Flags<type>(f1) | FBE::Flags<type>(f2); }\
|
||||
inline FBE::Flags<type> operator&(type f1, type f2) noexcept { return FBE::Flags<type>(f1) & FBE::Flags<type>(f2); }\
|
||||
inline FBE::Flags<type> operator^(type f1, type f2) noexcept { return FBE::Flags<type>(f1) ^ FBE::Flags<type>(f2); }
|
||||
|
||||
// Enum-based flags
|
||||
template <typename TEnum>
|
||||
class Flags
|
||||
{
|
||||
// Enum underlying type
|
||||
typedef typename std::make_unsigned<typename std::underlying_type<TEnum>::type>::type type;
|
||||
|
||||
public:
|
||||
Flags() noexcept : _value(0) {}
|
||||
explicit Flags(type value) noexcept : _value(value) {}
|
||||
explicit Flags(TEnum value) noexcept : _value((type)value) {}
|
||||
Flags(const Flags&) noexcept = default;
|
||||
Flags(Flags&&) noexcept = default;
|
||||
~Flags() noexcept = default;
|
||||
|
||||
Flags& operator=(type value) noexcept
|
||||
{ _value = value; return *this; }
|
||||
Flags& operator=(TEnum value) noexcept
|
||||
{ _value = (type)value; return *this; }
|
||||
Flags& operator=(const Flags&) noexcept = default;
|
||||
Flags& operator=(Flags&&) noexcept = default;
|
||||
|
||||
// Is any flag set?
|
||||
explicit operator bool() const noexcept { return isset(); }
|
||||
|
||||
// Is no flag set?
|
||||
bool operator!() const noexcept { return !isset(); }
|
||||
|
||||
// Reverse all flags
|
||||
Flags operator~() const noexcept { return Flags(~_value); }
|
||||
|
||||
// Flags logical assign operators
|
||||
Flags& operator&=(const Flags& flags) noexcept
|
||||
{ _value &= flags._value; return *this; }
|
||||
Flags& operator|=(const Flags& flags) noexcept
|
||||
{ _value |= flags._value; return *this; }
|
||||
Flags& operator^=(const Flags& flags) noexcept
|
||||
{ _value ^= flags._value; return *this; }
|
||||
|
||||
// Flags logical friend operators
|
||||
friend Flags operator&(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value & flags2._value); }
|
||||
friend Flags operator|(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value | flags2._value); }
|
||||
friend Flags operator^(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value ^ flags2._value); }
|
||||
|
||||
// Flags comparison
|
||||
friend bool operator==(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return flags1._value == flags2._value; }
|
||||
friend bool operator!=(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return flags1._value != flags2._value; }
|
||||
|
||||
// Convert to the enum value
|
||||
operator TEnum() const noexcept { return (TEnum)_value; }
|
||||
|
||||
//! Is any flag set?
|
||||
bool isset() const noexcept { return (_value != 0); }
|
||||
//! Is the given flag set?
|
||||
bool isset(type value) const noexcept { return (_value & value) != 0; }
|
||||
//! Is the given flag set?
|
||||
bool isset(TEnum value) const noexcept { return (_value & (type)value) != 0; }
|
||||
|
||||
// Get the enum value
|
||||
TEnum value() const noexcept { return (TEnum)_value; }
|
||||
// Get the underlying enum value
|
||||
type underlying() const noexcept { return _value; }
|
||||
// Get the bitset value
|
||||
std::bitset<sizeof(type) * 8> bitset() const noexcept { return {_value}; }
|
||||
|
||||
// Swap two instances
|
||||
void swap(Flags& flags) noexcept { using std::swap; swap(_value, flags._value); }
|
||||
template <typename UEnum>
|
||||
friend void swap(Flags<UEnum>& flags1, Flags<UEnum>& flags2) noexcept;
|
||||
|
||||
private:
|
||||
type _value;
|
||||
};
|
||||
|
||||
template <typename TEnum>
|
||||
inline void swap(Flags<TEnum>& flags1, Flags<TEnum>& flags2) noexcept
|
||||
{
|
||||
flags1.swap(flags2);
|
||||
}
|
||||
|
||||
// Get Epoch timestamp
|
||||
inline uint64_t epoch() { return 0ull; }
|
||||
// Get UTC timestamp
|
||||
uint64_t utc();
|
||||
|
||||
//! Universally unique identifier (UUID)
|
||||
/*!
|
||||
A universally unique identifier (UUID) is an identifier standard used
|
||||
in software construction. This implementation generates the following
|
||||
UUID types:
|
||||
- Nil UUID0 (all bits set to zero)
|
||||
- Sequential UUID1 (time based version)
|
||||
- Random UUID4 (randomly or pseudo-randomly generated version)
|
||||
|
||||
A UUID is simply a 128-bit value: "123e4567-e89b-12d3-a456-426655440000"
|
||||
|
||||
https://en.wikipedia.org/wiki/Universally_unique_identifier
|
||||
https://www.ietf.org/rfc/rfc4122.txt
|
||||
*/
|
||||
class uuid_t
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
uuid_t() : _data() { _data.fill(0); }
|
||||
//! Initialize UUID with a given string
|
||||
/*!
|
||||
\param uuid - UUID string
|
||||
*/
|
||||
explicit uuid_t(const std::string& uuid);
|
||||
//! Initialize UUID with a given 16 bytes data buffer
|
||||
/*!
|
||||
\param data - UUID 16 bytes data buffer
|
||||
*/
|
||||
explicit uuid_t(const std::array<uint8_t, 16>& data) : _data(data) {}
|
||||
uuid_t(const uuid_t&) = default;
|
||||
uuid_t(uuid_t&&) noexcept = default;
|
||||
~uuid_t() = default;
|
||||
|
||||
uuid_t& operator=(const std::string& uuid)
|
||||
{ _data = uuid_t(uuid).data(); return *this; }
|
||||
uuid_t& operator=(const std::array<uint8_t, 16>& data)
|
||||
{ _data = data; return *this; }
|
||||
uuid_t& operator=(const uuid_t&) = default;
|
||||
uuid_t& operator=(uuid_t&&) noexcept = default;
|
||||
|
||||
// UUID comparison
|
||||
friend bool operator==(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data == uuid2._data; }
|
||||
friend bool operator!=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data != uuid2._data; }
|
||||
friend bool operator<(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data < uuid2._data; }
|
||||
friend bool operator>(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data > uuid2._data; }
|
||||
friend bool operator<=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data <= uuid2._data; }
|
||||
friend bool operator>=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data >= uuid2._data; }
|
||||
|
||||
//! Check if the UUID is nil UUID0 (all bits set to zero)
|
||||
explicit operator bool() const noexcept { return *this != nil(); }
|
||||
|
||||
//! Get the UUID data buffer
|
||||
std::array<uint8_t, 16>& data() noexcept { return _data; }
|
||||
//! Get the UUID data buffer
|
||||
const std::array<uint8_t, 16>& data() const noexcept { return _data; }
|
||||
|
||||
//! Get string from the current UUID in format "00000000-0000-0000-0000-000000000000"
|
||||
std::string string() const;
|
||||
|
||||
//! Generate nil UUID0 (all bits set to zero)
|
||||
static uuid_t nil() { return uuid_t(); }
|
||||
//! Generate sequential UUID1 (time based version)
|
||||
static uuid_t sequential();
|
||||
//! Generate random UUID4 (randomly or pseudo-randomly generated version)
|
||||
static uuid_t random();
|
||||
|
||||
//! Output instance into the given output stream
|
||||
friend std::ostream& operator<<(std::ostream& os, const uuid_t& uuid)
|
||||
{ os << uuid.string(); return os; }
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
//! Store logging format
|
||||
friend CppLogging::Record& operator<<(CppLogging::Record& record, const uuid_t& uuid);
|
||||
#endif
|
||||
|
||||
//! Swap two instances
|
||||
void swap(uuid_t& uuid) noexcept
|
||||
{ using std::swap; swap(_data, uuid._data); }
|
||||
friend void swap(uuid_t& uuid1, uuid_t& uuid2) noexcept
|
||||
{ uuid1.swap(uuid2); }
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 16> _data;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<FBE::uuid_t>
|
||||
{
|
||||
typedef FBE::uuid_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
std::hash<uint8_t> hasher;
|
||||
for (size_t i = 0; i < value.data().size(); ++i)
|
||||
result = result * 31 + hasher(value.data()[i]);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding buffer based on the dynamic byte buffer
|
||||
class FBEBuffer
|
||||
{
|
||||
public:
|
||||
FBEBuffer() : _data(nullptr), _capacity(0), _size(0), _offset(0) {}
|
||||
// Initialize the read buffer with the given byte buffer and offset
|
||||
explicit FBEBuffer(const void* data, size_t size, size_t offset = 0) { attach(data, size, offset); }
|
||||
// Initialize the read buffer with the given byte vector and offset
|
||||
explicit FBEBuffer(const std::vector<uint8_t>& buffer, size_t offset = 0) { attach(buffer, offset); }
|
||||
// Initialize the read buffer with another buffer and offset
|
||||
explicit FBEBuffer(const FBEBuffer& buffer, size_t offset = 0) { attach(buffer.data(), buffer.size(), offset); }
|
||||
// Initialize the write buffer with the given capacity
|
||||
explicit FBEBuffer(size_t capacity) : FBEBuffer() { reserve(capacity); }
|
||||
FBEBuffer(const FBEBuffer&) = delete;
|
||||
FBEBuffer(FBEBuffer&&) noexcept = delete;
|
||||
~FBEBuffer() { if (_capacity > 0) std::free(_data); }
|
||||
|
||||
FBEBuffer& operator=(const FBEBuffer&) = delete;
|
||||
FBEBuffer& operator=(FBEBuffer&&) noexcept = delete;
|
||||
|
||||
bool empty() const noexcept { return (_data == nullptr) || (_size == 0); }
|
||||
const uint8_t* data() const noexcept { return _data; }
|
||||
uint8_t* data() noexcept { return _data; }
|
||||
size_t capacity() const noexcept { return _capacity; }
|
||||
size_t size() const noexcept { return _size; }
|
||||
size_t offset() const noexcept { return _offset; }
|
||||
|
||||
// Attach the given buffer with a given offset to the current read buffer
|
||||
void attach(const void* data, size_t size, size_t offset = 0);
|
||||
// Attach the given byte vector with a given offset to the current read buffer
|
||||
void attach(const std::vector<uint8_t>& buffer, size_t offset = 0);
|
||||
|
||||
// Clone the given buffer with a given offset to the current buffer
|
||||
void clone(const void* data, size_t size, size_t offset = 0);
|
||||
// Clone the given vector with a given offset to the current buffer
|
||||
void clone(const std::vector<uint8_t>& buffer, size_t offset = 0);
|
||||
|
||||
// Allocate memory in the current write buffer and return offset to the allocated memory block
|
||||
size_t allocate(size_t size);
|
||||
// Remove some memory of the given size from the current write buffer
|
||||
void remove(size_t offset, size_t size);
|
||||
// Reserve memory of the given capacity in the current write buffer
|
||||
void reserve(size_t capacity);
|
||||
// Resize the current write buffer
|
||||
void resize(size_t size);
|
||||
// Reset the current write buffer and its offset
|
||||
void reset();
|
||||
|
||||
// Shift the current write buffer offset
|
||||
void shift(size_t offset) { _offset += offset; }
|
||||
// Unshift the current write buffer offset
|
||||
void unshift(size_t offset) { _offset -= offset; }
|
||||
|
||||
private:
|
||||
uint8_t* _data;
|
||||
size_t _capacity;
|
||||
size_t _size;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding base model
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
Model() : Model(nullptr) {}
|
||||
Model(const std::shared_ptr<FBEBuffer>& buffer) { _buffer = buffer ? buffer : std::make_shared<FBEBuffer>(); }
|
||||
Model(const Model&) = default;
|
||||
Model(Model&&) noexcept = default;
|
||||
~Model() = default;
|
||||
|
||||
Model& operator=(const Model&) = default;
|
||||
Model& operator=(Model&&) noexcept = default;
|
||||
|
||||
// Get the model buffer
|
||||
FBEBuffer& buffer() noexcept { return *_buffer; }
|
||||
const FBEBuffer& buffer() const noexcept { return *_buffer; }
|
||||
|
||||
// Attach the model buffer
|
||||
void attach(const void* data, size_t size, size_t offset = 0) { _buffer->attach(data, size, offset); }
|
||||
void attach(const std::vector<uint8_t>& buffer, size_t offset = 0) { _buffer->attach(buffer, offset); }
|
||||
void attach(const FBEBuffer& buffer, size_t offset = 0) { _buffer->attach(buffer.data(), buffer.size(), offset); }
|
||||
|
||||
// Model buffer operations
|
||||
size_t allocate(size_t size) { return _buffer->allocate(size); }
|
||||
void remove(size_t offset, size_t size) { _buffer->remove(offset, size); }
|
||||
void reserve(size_t capacity) { _buffer->reserve(capacity); }
|
||||
void resize(size_t size) { _buffer->resize(size); }
|
||||
void reset() { _buffer->reset(); }
|
||||
void shift(size_t offset) { _buffer->shift(offset); }
|
||||
void unshift(size_t offset) { _buffer->unshift(offset); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<FBEBuffer> _buffer;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
436
fbe/user_model/fbe_final_models.cpp
Normal file
436
fbe/user_model/fbe_final_models.cpp
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "fbe_final_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
uint64_t FinalModel<decimal_t>::extract(double a) noexcept
|
||||
{
|
||||
uint64_t result;
|
||||
std::memcpy(&result, &a, sizeof(double));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t FinalModel<decimal_t>::uint32x32(uint32_t a, uint32_t b) noexcept
|
||||
{
|
||||
return (uint64_t)a * (uint64_t)b;
|
||||
}
|
||||
|
||||
void FinalModel<decimal_t>::uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept
|
||||
{
|
||||
uint64_t low = uint32x32((uint32_t)a, (uint32_t)b);
|
||||
uint64_t mid = uint32x32((uint32_t)a, (uint32_t)(b >> 32));
|
||||
uint64_t high = uint32x32((uint32_t)(a >> 32), (uint32_t)(b >> 32));
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
mid = uint32x32((uint32_t)(a >> 32), (uint32_t)b);
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
if (high > 0xFFFFFFFFu)
|
||||
{
|
||||
low64 = 0;
|
||||
high32 = 0;
|
||||
}
|
||||
low64 = low;
|
||||
high32 = (uint32_t)high;
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::get(decimal_t& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
// Value taken via reverse engineering the double that corresponds to 2^64
|
||||
const double ds2to64 = 1.8446744073709552e+019;
|
||||
|
||||
// Read decimal parts
|
||||
uint64_t low = *((const uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
uint32_t high = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8));
|
||||
uint32_t flags = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12));
|
||||
|
||||
// Calculate decimal value
|
||||
double dValue = ((double)low + (double)high * ds2to64) / pow(10.0, (uint8_t)(flags >> 16));
|
||||
if (flags & 0x80000000)
|
||||
dValue = -dValue;
|
||||
|
||||
value = dValue;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::set(decimal_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
// The most we can scale by is 10^28, which is just slightly more
|
||||
// than 2^93. So a float with an exponent of -94 could just
|
||||
// barely reach 0.5, but smaller exponents will always round to zero.
|
||||
const uint32_t DBLBIAS = 1022;
|
||||
|
||||
// Get exponent value
|
||||
double dValue = (double)value;
|
||||
int32_t iExp = (int32_t)(((uint32_t)(extract(dValue) >> 52) & 0x7FFu) - DBLBIAS);
|
||||
if ((iExp < -94) || (iExp > 96))
|
||||
{
|
||||
// Value too big for .NET Decimal (exponent is limited to [-94, 96])
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (dValue < 0)
|
||||
{
|
||||
dValue = -dValue;
|
||||
flags = 0x80000000;
|
||||
}
|
||||
|
||||
// Round the input to a 15-digit integer. The R8 format has
|
||||
// only 15 digits of precision, and we want to keep garbage digits
|
||||
// out of the Decimal were making.
|
||||
|
||||
// Calculate max power of 10 input value could have by multiplying
|
||||
// the exponent by log10(2). Using scaled integer multiplcation,
|
||||
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
|
||||
int32_t iPower = 14 - ((iExp * 19728) >> 16);
|
||||
|
||||
// iPower is between -14 and 43
|
||||
if (iPower >= 0)
|
||||
{
|
||||
// We have less than 15 digits, scale input up.
|
||||
if (iPower > 28)
|
||||
iPower = 28;
|
||||
|
||||
dValue *= pow(10.0, iPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((iPower != -1) || (dValue >= 1E15))
|
||||
dValue /= pow(10.0, -iPower);
|
||||
else
|
||||
iPower = 0; // didn't scale it
|
||||
}
|
||||
|
||||
assert(dValue < 1E15);
|
||||
if ((dValue < 1E14) && (iPower < 28))
|
||||
{
|
||||
dValue *= 10;
|
||||
iPower++;
|
||||
assert(dValue >= 1E14);
|
||||
}
|
||||
|
||||
// Round to int64
|
||||
uint64_t ulMant;
|
||||
ulMant = (uint64_t)(int64_t)dValue;
|
||||
dValue -= (int64_t)ulMant; // difference between input & integer
|
||||
if ((dValue > 0.5) || ((dValue == 0.5) && ((ulMant & 1) != 0)))
|
||||
ulMant++;
|
||||
|
||||
if (ulMant == 0)
|
||||
{
|
||||
// Mantissa is 0
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
if (iPower < 0)
|
||||
{
|
||||
// Add -iPower factors of 10, -iPower <= (29 - 15) = 14
|
||||
iPower = -iPower;
|
||||
if (iPower < 10)
|
||||
{
|
||||
double pow10 = (double)powl(10.0, iPower);
|
||||
uint64_t low64 = uint32x32((uint32_t)ulMant, (uint32_t)pow10);
|
||||
uint64_t high64 = uint32x32((uint32_t)(ulMant >> 32), (uint32_t)pow10);
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)low64;
|
||||
high64 += low64 >> 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4)) = (uint32_t)high64;
|
||||
high64 >>= 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = (uint32_t)high64;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have a big power of 10.
|
||||
assert(iPower <= 14);
|
||||
uint64_t low64;
|
||||
uint32_t high32;
|
||||
uint64x64(ulMant, (uint64_t)pow(10.0, iPower), low64, high32);
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = low64;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = high32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Factor out powers of 10 to reduce the scale, if possible.
|
||||
// The maximum number we could factor out would be 14. This
|
||||
// comes from the fact we have a 15-digit number, and the
|
||||
// MSD must be non-zero -- but the lower 14 digits could be
|
||||
// zero. Note also the scale factor is never negative, so
|
||||
// we can't scale by any more than the power we used to
|
||||
// get the integer.
|
||||
int lmax = iPower;
|
||||
if (lmax > 14)
|
||||
lmax = 14;
|
||||
|
||||
if ((((uint8_t)ulMant) == 0) && (lmax >= 8))
|
||||
{
|
||||
const uint32_t den = 100000000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 8;
|
||||
lmax -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 0xF) == 0) && (lmax >= 4))
|
||||
{
|
||||
const uint32_t den = 10000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 4;
|
||||
lmax -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 3) == 0) && (lmax >= 2))
|
||||
{
|
||||
const uint32_t den = 100;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 2;
|
||||
lmax -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 1) == 0) && (lmax >= 1))
|
||||
{
|
||||
const uint32_t den = 10;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower--;
|
||||
}
|
||||
}
|
||||
|
||||
flags |= (uint32_t)iPower << 16;
|
||||
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = ulMant;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = 0;
|
||||
}
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12)) = flags;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::get(uuid_t& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
std::memcpy(value.data().data(), (const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), fbe_size());
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::set(uuid_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
std::memcpy((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), value.data().data(), fbe_size());
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::get(void* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_bytes_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), result);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::get(std::vector<uint8_t>& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
const char* fbe_bytes = (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4);
|
||||
value.assign(fbe_bytes, fbe_bytes + fbe_bytes_size);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::set(const void* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = (uint32_t)size;
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_bytes_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), data, fbe_bytes_size);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::get(char* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_string_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), result);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::get(std::string& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::set(const char* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)size;
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), data, fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::set(const std::string& value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)value.size();
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), value.data(), fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
457
fbe/user_model/fbe_final_models.h
Normal file
457
fbe/user_model/fbe_final_models.h
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding base final model
|
||||
template <typename T, typename TBase = T>
|
||||
class FinalModelBase
|
||||
{
|
||||
public:
|
||||
FinalModelBase(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(T value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return sizeof(TBase); }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the field value
|
||||
size_t get(T& value) const noexcept;
|
||||
// Set the field value
|
||||
size_t set(T value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model
|
||||
template <typename T>
|
||||
class FinalModel : public FinalModelBase<T>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<T>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model bool specialization
|
||||
template <>
|
||||
class FinalModel<bool> : public FinalModelBase<bool, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<bool, uint8_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model char specialization
|
||||
template <>
|
||||
class FinalModel<char> : public FinalModelBase<char, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<char, uint8_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model wchar specialization
|
||||
template <>
|
||||
class FinalModel<wchar_t> : public FinalModelBase<wchar_t, uint32_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<wchar_t, uint32_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model decimal specialization
|
||||
template <>
|
||||
class FinalModel<decimal_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(decimal_t value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the decimal value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the decimal value
|
||||
size_t get(decimal_t& value) const noexcept;
|
||||
// Set the decimal value
|
||||
size_t set(decimal_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
static uint64_t extract(double a) noexcept;
|
||||
static uint64_t uint32x32(uint32_t a, uint32_t b) noexcept;
|
||||
static void uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model UUID specialization
|
||||
template <>
|
||||
class FinalModel<uuid_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(uuid_t value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the UUID value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the UUID value
|
||||
size_t get(uuid_t& value) const noexcept;
|
||||
// Set the UUID value
|
||||
size_t set(uuid_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model bytes specialization
|
||||
template <>
|
||||
class FinalModel<buffer_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const void* data, size_t size) const noexcept { return 4 + size; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const uint8_t (&data)[N]) const noexcept { return 4 + N; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const std::array<uint8_t, N>& data) const noexcept { return 4 + N; }
|
||||
size_t fbe_allocation_size(const std::vector<uint8_t>& value) const noexcept { return 4 + value.size(); }
|
||||
size_t fbe_allocation_size(const buffer_t& value) const noexcept { return 4 + value.size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the bytes value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the bytes value
|
||||
size_t get(void* data, size_t size) const noexcept;
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(uint8_t (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(std::array<uint8_t, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the bytes value
|
||||
size_t get(std::vector<uint8_t>& value) const noexcept;
|
||||
// Get the bytes value
|
||||
size_t get(buffer_t& value) const noexcept { return get(value.buffer()); }
|
||||
|
||||
// Set the bytes value
|
||||
size_t set(const void* data, size_t size);
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
size_t set(const uint8_t (&data)[N]) { return set(data, N); }
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
size_t set(const std::array<uint8_t, N>& data) { return set(data.data(), data.size()); }
|
||||
// Set the bytes value
|
||||
size_t set(const std::vector<uint8_t>& value) { return set(value.data(), value.size()); }
|
||||
// Set the bytes value
|
||||
size_t set(const buffer_t& value) { return set(value.buffer()); }
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model string specialization
|
||||
template <>
|
||||
class FinalModel<std::string>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const char* data, size_t size) const noexcept { return 4 + size; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const char (&data)[N]) const noexcept { return 4 + N; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const std::array<char, N>& data) const noexcept { return 4 + N; }
|
||||
size_t fbe_allocation_size(const std::string& value) const noexcept { return 4 + value.size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the string value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the string value
|
||||
size_t get(char* data, size_t size) const noexcept;
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(char (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(std::array<char, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the string value
|
||||
size_t get(std::string& value) const noexcept;
|
||||
|
||||
// Set the string value
|
||||
size_t set(const char* data, size_t size);
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
size_t set(const char (&data)[N]) { return set(data, N); }
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
size_t set(const std::array<char, N>& data) { return set(data.data(), data.size()); }
|
||||
// Set the string value
|
||||
size_t set(const std::string& value);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model optional specialization
|
||||
template <typename T>
|
||||
class FinalModel<std::optional<T>>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), value(buffer, 0) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::optional<T>& opt) const noexcept { return 1 + (opt ? value.fbe_allocation_size(opt.value()) : 0); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
//! Is the value present?
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
// Checks if the object contains a value
|
||||
bool has_value() const noexcept;
|
||||
|
||||
// Check if the optional value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the optional value
|
||||
size_t get(std::optional<T>& opt) const noexcept;
|
||||
// Set the optional value
|
||||
size_t set(const std::optional<T>& opt);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
// Base final model value
|
||||
FinalModel<T> value;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model array
|
||||
template <typename T, size_t N>
|
||||
class FinalModelArray
|
||||
{
|
||||
public:
|
||||
FinalModelArray(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
template <size_t S>
|
||||
size_t fbe_allocation_size(const T (&values)[S]) const noexcept;
|
||||
template <size_t S>
|
||||
size_t fbe_allocation_size(const std::array<T, S>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::vector<T>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the array is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the array as C-array
|
||||
template <size_t S>
|
||||
size_t get(T (&values)[S]) const noexcept;
|
||||
// Get the array as std::array
|
||||
template <size_t S>
|
||||
size_t get(std::array<T, S>& values) const noexcept;
|
||||
// Get the array as std::vector
|
||||
size_t get(std::vector<T>& values) const noexcept;
|
||||
|
||||
// Set the array as C-array
|
||||
template <size_t S>
|
||||
size_t set(const T (&values)[S]) noexcept;
|
||||
// Set the array as std::array
|
||||
template <size_t S>
|
||||
size_t set(const std::array<T, S>& values) noexcept;
|
||||
// Set the array as std::vector
|
||||
size_t set(const std::vector<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model vector
|
||||
template <typename T>
|
||||
class FinalModelVector
|
||||
{
|
||||
public:
|
||||
FinalModelVector(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::vector<T>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::list<T>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::set<T>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the vector is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the vector as std::vector
|
||||
size_t get(std::vector<T>& values) const noexcept;
|
||||
// Get the vector as std::list
|
||||
size_t get(std::list<T>& values) const noexcept;
|
||||
// Get the vector as std::set
|
||||
size_t get(std::set<T>& values) const noexcept;
|
||||
|
||||
// Set the vector as std::vector
|
||||
size_t set(const std::vector<T>& values) noexcept;
|
||||
// Set the vector as std::list
|
||||
size_t set(const std::list<T>& values) noexcept;
|
||||
// Set the vector as std::set
|
||||
size_t set(const std::set<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model map
|
||||
template <typename TKey, typename TValue>
|
||||
class FinalModelMap
|
||||
{
|
||||
public:
|
||||
FinalModelMap(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::map<TKey, TValue>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the map is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the map as std::map
|
||||
size_t get(std::map<TKey, TValue>& values) const noexcept;
|
||||
// Get the map as std::unordered_map
|
||||
size_t get(std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Set the map as std::map
|
||||
size_t set(const std::map<TKey, TValue>& values) noexcept;
|
||||
// Set the map as std::unordered_map
|
||||
size_t set(const std::unordered_map<TKey, TValue>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#include "fbe_final_models.inl"
|
||||
635
fbe/user_model/fbe_final_models.inl
Normal file
635
fbe/user_model/fbe_final_models.inl
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
namespace FBE {
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::get(T& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
value = (T)(*((const TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())));
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::set(T value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (TBase)value;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FinalModel<std::optional<T>>::has_value() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return (fbe_has_value != 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_has_value == 0)
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
size_t fbe_result = value.verify();
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::get(std::optional<T>& opt) const noexcept
|
||||
{
|
||||
opt = std::nullopt;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 1) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
if (!has_value())
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
T temp = T();
|
||||
size_t size = value.get(temp);
|
||||
opt.emplace(temp);
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::set(const std::optional<T>& opt)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 1) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint8_t fbe_has_value = opt ? 1 : 0;
|
||||
*((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_has_value;
|
||||
if (fbe_has_value == 0)
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
size_t size = 0;
|
||||
if (opt)
|
||||
size = value.set(opt.value());
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const T (&values)[S]) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const std::array<T, S>& values) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const std::vector<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
size_t offset = fbe_model.verify();
|
||||
if (offset == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::get(T (&values)[S]) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::get(std::array<T, S>& values) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
values.reserve(N);
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::set(const T (&values)[S]) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::set(const std::array<T, S>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::vector<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::list<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::set<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
size_t offset = fbe_model.verify();
|
||||
if (offset == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
values.reserve(fbe_vector_size);
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::list<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::set<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::list<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::set<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::fbe_allocation_size(const std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size += fbe_model_key.fbe_allocation_size(value.first);
|
||||
size += fbe_model_value.fbe_allocation_size(value.second);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::fbe_allocation_size(const std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size += fbe_model_key.fbe_allocation_size(value.first);
|
||||
size += fbe_model_value.fbe_allocation_size(value.second);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.verify();
|
||||
if (offset_key == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size += offset_key;
|
||||
size_t offset_value = fbe_model_value.verify();
|
||||
if (offset_value == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.get(value);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
values.emplace(key, value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.get(value);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
values.emplace(key, value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::set(const std::map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.set(value.first);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.set(value.second);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::set(const std::unordered_map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.set(value.first);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.set(value.second);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
514
fbe/user_model/fbe_models.cpp
Normal file
514
fbe/user_model/fbe_models.cpp
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#include "fbe_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
uint64_t FieldModel<decimal_t>::extract(double a) noexcept
|
||||
{
|
||||
uint64_t result;
|
||||
std::memcpy(&result, &a, sizeof(double));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t FieldModel<decimal_t>::uint32x32(uint32_t a, uint32_t b) noexcept
|
||||
{
|
||||
return (uint64_t)a * (uint64_t)b;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept
|
||||
{
|
||||
uint64_t low = uint32x32((uint32_t)a, (uint32_t)b);
|
||||
uint64_t mid = uint32x32((uint32_t)a, (uint32_t)(b >> 32));
|
||||
uint64_t high = uint32x32((uint32_t)(a >> 32), (uint32_t)(b >> 32));
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
mid = uint32x32((uint32_t)(a >> 32), (uint32_t)b);
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
if (high > 0xFFFFFFFFu)
|
||||
{
|
||||
low64 = 0;
|
||||
high32 = 0;
|
||||
}
|
||||
low64 = low;
|
||||
high32 = (uint32_t)high;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::get(decimal_t& value, decimal_t defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
// Value taken via reverse engineering the double that corresponds to 2^64
|
||||
const double ds2to64 = 1.8446744073709552e+019;
|
||||
|
||||
// Read decimal parts
|
||||
uint64_t low = *((const uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
uint32_t high = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8));
|
||||
uint32_t flags = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12));
|
||||
|
||||
// Calculate decimal value
|
||||
double dValue = ((double)low + (double)high * ds2to64) / pow(10.0, (uint8_t)(flags >> 16));
|
||||
if (flags & 0x80000000)
|
||||
dValue = -dValue;
|
||||
|
||||
value = dValue;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::set(decimal_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
// The most we can scale by is 10^28, which is just slightly more
|
||||
// than 2^93. So a float with an exponent of -94 could just
|
||||
// barely reach 0.5, but smaller exponents will always round to zero.
|
||||
const uint32_t DBLBIAS = 1022;
|
||||
|
||||
// Get exponent value
|
||||
double dValue = (double)value;
|
||||
int32_t iExp = (int32_t)(((uint32_t)(extract(dValue) >> 52) & 0x7FFu) - DBLBIAS);
|
||||
if ((iExp < -94) || (iExp > 96))
|
||||
{
|
||||
// Value too big for .NET Decimal (exponent is limited to [-94, 96])
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (dValue < 0)
|
||||
{
|
||||
dValue = -dValue;
|
||||
flags = 0x80000000;
|
||||
}
|
||||
|
||||
// Round the input to a 15-digit integer. The R8 format has
|
||||
// only 15 digits of precision, and we want to keep garbage digits
|
||||
// out of the Decimal were making.
|
||||
|
||||
// Calculate max power of 10 input value could have by multiplying
|
||||
// the exponent by log10(2). Using scaled integer multiplcation,
|
||||
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
|
||||
int32_t iPower = 14 - ((iExp * 19728) >> 16);
|
||||
|
||||
// iPower is between -14 and 43
|
||||
if (iPower >= 0)
|
||||
{
|
||||
// We have less than 15 digits, scale input up.
|
||||
if (iPower > 28)
|
||||
iPower = 28;
|
||||
|
||||
dValue *= pow(10.0, iPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((iPower != -1) || (dValue >= 1E15))
|
||||
dValue /= pow(10.0, -iPower);
|
||||
else
|
||||
iPower = 0; // didn't scale it
|
||||
}
|
||||
|
||||
assert(dValue < 1E15);
|
||||
if ((dValue < 1E14) && (iPower < 28))
|
||||
{
|
||||
dValue *= 10;
|
||||
iPower++;
|
||||
assert(dValue >= 1E14);
|
||||
}
|
||||
|
||||
// Round to int64
|
||||
uint64_t ulMant;
|
||||
ulMant = (uint64_t)(int64_t)dValue;
|
||||
dValue -= (int64_t)ulMant; // difference between input & integer
|
||||
if ((dValue > 0.5) || ((dValue == 0.5) && ((ulMant & 1) != 0)))
|
||||
ulMant++;
|
||||
|
||||
if (ulMant == 0)
|
||||
{
|
||||
// Mantissa is 0
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iPower < 0)
|
||||
{
|
||||
// Add -iPower factors of 10, -iPower <= (29 - 15) = 14
|
||||
iPower = -iPower;
|
||||
if (iPower < 10)
|
||||
{
|
||||
double pow10 = (double)powl(10.0, iPower);
|
||||
uint64_t low64 = uint32x32((uint32_t)ulMant, (uint32_t)pow10);
|
||||
uint64_t high64 = uint32x32((uint32_t)(ulMant >> 32), (uint32_t)pow10);
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)low64;
|
||||
high64 += low64 >> 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4)) = (uint32_t)high64;
|
||||
high64 >>= 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = (uint32_t)high64;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have a big power of 10.
|
||||
assert(iPower <= 14);
|
||||
uint64_t low64;
|
||||
uint32_t high32;
|
||||
uint64x64(ulMant, (uint64_t)pow(10.0, iPower), low64, high32);
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = low64;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = high32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Factor out powers of 10 to reduce the scale, if possible.
|
||||
// The maximum number we could factor out would be 14. This
|
||||
// comes from the fact we have a 15-digit number, and the
|
||||
// MSD must be non-zero -- but the lower 14 digits could be
|
||||
// zero. Note also the scale factor is never negative, so
|
||||
// we can't scale by any more than the power we used to
|
||||
// get the integer.
|
||||
int lmax = iPower;
|
||||
if (lmax > 14)
|
||||
lmax = 14;
|
||||
|
||||
if ((((uint8_t)ulMant) == 0) && (lmax >= 8))
|
||||
{
|
||||
const uint32_t den = 100000000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 8;
|
||||
lmax -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 0xF) == 0) && (lmax >= 4))
|
||||
{
|
||||
const uint32_t den = 10000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 4;
|
||||
lmax -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 3) == 0) && (lmax >= 2))
|
||||
{
|
||||
const uint32_t den = 100;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 2;
|
||||
lmax -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 1) == 0) && (lmax >= 1))
|
||||
{
|
||||
const uint32_t den = 10;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower--;
|
||||
}
|
||||
}
|
||||
|
||||
flags |= (uint32_t)iPower << 16;
|
||||
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = ulMant;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = 0;
|
||||
}
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12)) = flags;
|
||||
}
|
||||
|
||||
void FieldModel<uuid_t>::get(uuid_t& value, uuid_t defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(value.data().data(), (const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), fbe_size());
|
||||
}
|
||||
|
||||
void FieldModel<uuid_t>::set(uuid_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
std::memcpy((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), value.data().data(), fbe_size());
|
||||
}
|
||||
|
||||
size_t FieldModel<buffer_t>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_bytes_offset == 0) || ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
return (size_t)(4 + fbe_bytes_size);
|
||||
}
|
||||
|
||||
bool FieldModel<buffer_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<buffer_t>::get(void* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_bytes_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FieldModel<buffer_t>::get(std::vector<uint8_t>& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
const char* fbe_bytes = (const char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4);
|
||||
value.assign(fbe_bytes, fbe_bytes + fbe_bytes_size);
|
||||
}
|
||||
|
||||
void FieldModel<buffer_t>::set(const void* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_size = (uint32_t)size;
|
||||
uint32_t fbe_bytes_offset = (uint32_t)(_buffer.allocate(4 + fbe_bytes_size) - _buffer.offset());
|
||||
assert(((fbe_bytes_offset > 0) && ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_bytes_offset == 0) || ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_bytes_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset)) = fbe_bytes_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4), data, fbe_bytes_size);
|
||||
}
|
||||
|
||||
size_t FieldModel<std::string>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
return (size_t)(4 + fbe_string_size);
|
||||
}
|
||||
|
||||
bool FieldModel<std::string>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_string_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<std::string>::get(char* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_string_offset == 0)
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_string_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::get(std::string& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + _offset));
|
||||
if (fbe_string_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::get(std::string& value, const std::string& defaults) const noexcept
|
||||
{
|
||||
value = defaults;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + _offset));
|
||||
if (fbe_string_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::set(const char* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)size;
|
||||
uint32_t fbe_string_offset = (uint32_t)(_buffer.allocate(4 + fbe_string_size) - _buffer.offset());
|
||||
assert(((fbe_string_offset > 0) && ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset)) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), data, fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::set(const std::string& value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)value.size();
|
||||
uint32_t fbe_string_offset = (uint32_t)(_buffer.allocate(4 + fbe_string_size) - _buffer.offset());
|
||||
assert(((fbe_string_offset > 0) && ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset)) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), value.data(), fbe_string_size);
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
469
fbe/user_model/fbe_models.h
Normal file
469
fbe/user_model/fbe_models.h
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding base field model
|
||||
template <typename T, typename TBase = T>
|
||||
class FieldModelBase
|
||||
{
|
||||
public:
|
||||
FieldModelBase(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return sizeof(TBase); }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the field value
|
||||
void get(T& value, T defaults = (T)0) const noexcept;
|
||||
// Set the field value
|
||||
void set(T value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model
|
||||
template <typename T>
|
||||
class FieldModel : public FieldModelBase<T>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<T>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model bool specialization
|
||||
template <>
|
||||
class FieldModel<bool> : public FieldModelBase<bool, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<bool, uint8_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model char specialization
|
||||
template <>
|
||||
class FieldModel<char> : public FieldModelBase<char, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<char, uint8_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model wchar specialization
|
||||
template <>
|
||||
class FieldModel<wchar_t> : public FieldModelBase<wchar_t, uint32_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<wchar_t, uint32_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model decimal specialization
|
||||
template <>
|
||||
class FieldModel<decimal_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the decimal value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the decimal value
|
||||
void get(decimal_t& value, decimal_t defaults = decimal_t()) const noexcept;
|
||||
// Set the decimal value
|
||||
void set(decimal_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
static uint64_t extract(double a) noexcept;
|
||||
static uint64_t uint32x32(uint32_t a, uint32_t b) noexcept;
|
||||
static void uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model UUID specialization
|
||||
template <>
|
||||
class FieldModel<uuid_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the UUID value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the UUID value
|
||||
void get(uuid_t& value, uuid_t defaults = uuid_t::nil()) const noexcept;
|
||||
// Set the UUID value
|
||||
void set(uuid_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model bytes specialization
|
||||
template <>
|
||||
class FieldModel<buffer_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the bytes value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the bytes value
|
||||
size_t get(void* data, size_t size) const noexcept;
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(uint8_t (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(std::array<uint8_t, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the bytes value
|
||||
void get(std::vector<uint8_t>& value) const noexcept;
|
||||
// Get the bytes value
|
||||
void get(buffer_t& value) const noexcept { get(value.buffer()); }
|
||||
|
||||
// Set the bytes value
|
||||
void set(const void* data, size_t size);
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
void set(const uint8_t (&data)[N]) { set(data, N); }
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
void set(const std::array<uint8_t, N>& data) { set(data.data(), data.size()); }
|
||||
// Set the bytes value
|
||||
void set(const std::vector<uint8_t>& value) { set(value.data(), value.size()); }
|
||||
// Set the bytes value
|
||||
void set(const buffer_t& value) { set(value.buffer()); }
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model string specialization
|
||||
template <>
|
||||
class FieldModel<std::string>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the string value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the string value
|
||||
size_t get(char* data, size_t size) const noexcept;
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(char (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(std::array<char, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the string value
|
||||
void get(std::string& value) const noexcept;
|
||||
// Get the string value
|
||||
void get(std::string& value, const std::string& defaults) const noexcept;
|
||||
|
||||
// Set the string value
|
||||
void set(const char* data, size_t size);
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
void set(const char (&data)[N]) { set(data, N); }
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
void set(const std::array<char, N>& data) { set(data.data(), data.size()); }
|
||||
// Set the string value
|
||||
void set(const std::string& value);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model optional specialization
|
||||
template <typename T>
|
||||
class FieldModel<std::optional<T>>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), value(buffer, 0) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 1 + 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
//! Is the value present?
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
// Checks if the object contains a value
|
||||
bool has_value() const noexcept;
|
||||
|
||||
// Check if the optional value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the optional value (being phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the optional value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the optional value
|
||||
void get(std::optional<T>& opt, const std::optional<T>& defaults = std::nullopt) const noexcept;
|
||||
|
||||
// Set the optional value (begin phase)
|
||||
size_t set_begin(bool has_value);
|
||||
// Set the optional value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the optional value
|
||||
void set(const std::optional<T>& opt);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
// Base field model value
|
||||
FieldModel<T> value;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model array
|
||||
template <typename T, size_t N>
|
||||
class FieldModelArray
|
||||
{
|
||||
public:
|
||||
FieldModelArray(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), _model(buffer, offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return N * _model.fbe_size(); }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the array
|
||||
const uint8_t* data() const noexcept;
|
||||
// Get the array
|
||||
uint8_t* data() noexcept;
|
||||
// Get the array offset
|
||||
size_t offset() const noexcept { return 0; }
|
||||
// Get the array size
|
||||
size_t size() const noexcept { return N; }
|
||||
|
||||
// Array index operator
|
||||
FieldModel<T> operator[](size_t index) const noexcept;
|
||||
|
||||
// Check if the array is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the array as C-array
|
||||
template <size_t S>
|
||||
void get(T (&values)[S]) const noexcept;
|
||||
// Get the array as std::array
|
||||
template <size_t S>
|
||||
void get(std::array<T, S>& values) const noexcept;
|
||||
// Get the array as std::vector
|
||||
void get(std::vector<T>& values) const noexcept;
|
||||
|
||||
// Set the array as C-array
|
||||
template <size_t S>
|
||||
void set(const T (&values)[S]) noexcept;
|
||||
// Set the array as std::array
|
||||
template <size_t S>
|
||||
void set(const std::array<T, S>& values) noexcept;
|
||||
// Set the array as std::vector
|
||||
void set(const std::vector<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
FieldModel<T> _model;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model vector
|
||||
template <typename T>
|
||||
class FieldModelVector
|
||||
{
|
||||
public:
|
||||
FieldModelVector(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the vector offset
|
||||
size_t offset() const noexcept;
|
||||
// Get the vector size
|
||||
size_t size() const noexcept;
|
||||
|
||||
// Vector index operator
|
||||
FieldModel<T> operator[](size_t index) const noexcept;
|
||||
|
||||
// Resize the vector and get its first model
|
||||
FieldModel<T> resize(size_t size);
|
||||
|
||||
// Check if the vector is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the vector as std::vector
|
||||
void get(std::vector<T>& values) const noexcept;
|
||||
// Get the vector as std::list
|
||||
void get(std::list<T>& values) const noexcept;
|
||||
// Get the vector as std::set
|
||||
void get(std::set<T>& values) const noexcept;
|
||||
|
||||
// Set the vector as std::vector
|
||||
void set(const std::vector<T>& values) noexcept;
|
||||
// Set the vector as std::list
|
||||
void set(const std::list<T>& values) noexcept;
|
||||
// Set the vector as std::set
|
||||
void set(const std::set<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model map
|
||||
template <typename TKey, typename TValue>
|
||||
class FieldModelMap
|
||||
{
|
||||
public:
|
||||
FieldModelMap(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the map offset
|
||||
size_t offset() const noexcept;
|
||||
// Get the map size
|
||||
size_t size() const noexcept;
|
||||
|
||||
// Map index operator
|
||||
std::pair<FieldModel<TKey>, FieldModel<TValue>> operator[](size_t index) const noexcept;
|
||||
|
||||
// Resize the map and get its first model
|
||||
std::pair<FieldModel<TKey>, FieldModel<TValue>> resize(size_t size);
|
||||
|
||||
// Check if the map is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the map as std::map
|
||||
void get(std::map<TKey, TValue>& values) const noexcept;
|
||||
// Get the map as std::unordered_map
|
||||
void get(std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Set the map as std::map
|
||||
void set(const std::map<TKey, TValue>& values) noexcept;
|
||||
// Set the map as std::unordered_map
|
||||
void set(const std::unordered_map<TKey, TValue>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#include "fbe_models.inl"
|
||||
687
fbe/user_model/fbe_models.inl
Normal file
687
fbe/user_model/fbe_models.inl
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
|
||||
namespace FBE {
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline void FieldModelBase<T, TBase>::get(T& value, T defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
value = (T)(*((const TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())));
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline void FieldModelBase<T, TBase>::set(T value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
*((TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (TBase)value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::fbe_extra() const noexcept
|
||||
{
|
||||
if (!has_value())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
if ((fbe_optional_offset == 0) || ((_buffer.offset() + fbe_optional_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
size_t fbe_result = value.fbe_size() + value.fbe_extra();
|
||||
_buffer.unshift(fbe_optional_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModel<std::optional<T>>::has_value() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return (fbe_has_value != 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModel<std::optional<T>>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_has_value == 0)
|
||||
return true;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
if (fbe_optional_offset == 0)
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
bool fbe_result = value.verify();
|
||||
_buffer.unshift(fbe_optional_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::get_begin() const noexcept
|
||||
{
|
||||
if (!has_value())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
assert((fbe_optional_offset > 0) && "Model is broken!");
|
||||
if (fbe_optional_offset == 0)
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
return fbe_optional_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::get(std::optional<T>& opt, const std::optional<T>& defaults) const noexcept
|
||||
{
|
||||
opt = defaults;
|
||||
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
T temp = T();
|
||||
value.get(temp);
|
||||
opt.emplace(temp);
|
||||
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::set_begin(bool has_value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint8_t fbe_has_value = has_value ? 1 : 0;
|
||||
*((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_has_value;
|
||||
if (fbe_has_value == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_size = (uint32_t)value.fbe_size();
|
||||
uint32_t fbe_optional_offset = (uint32_t)(_buffer.allocate(fbe_optional_size) - _buffer.offset());
|
||||
assert(((fbe_optional_offset > 0) && ((_buffer.offset() + fbe_optional_offset + fbe_optional_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_optional_offset == 0) || ((_buffer.offset() + fbe_optional_offset + fbe_optional_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1)) = fbe_optional_offset;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
return fbe_optional_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::set(const std::optional<T>& opt)
|
||||
{
|
||||
size_t fbe_begin = set_begin(opt.has_value());
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
if (opt)
|
||||
value.set(opt.value());
|
||||
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline const uint8_t* FieldModelArray<T, N>::data() const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
return _buffer.data() + _buffer.offset() + fbe_offset();
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline uint8_t* FieldModelArray<T, N>::data() noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
return _buffer.data() + _buffer.offset() + fbe_offset();
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline FieldModel<T> FieldModelArray<T, N>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
assert((index < N) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
fbe_model.fbe_shift(index * fbe_model.fbe_size());
|
||||
return fbe_model;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline bool FieldModelArray<T, N>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return false;
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model.verify())
|
||||
return false;
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::get(T (&values)[S]) const noexcept
|
||||
{
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::get(std::array<T, S>& values) const noexcept
|
||||
{
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline void FieldModelArray<T, N>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
values.reserve(N);
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::set(const T (&values)[S]) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::set(const std::array<T, S>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline void FieldModelArray<T, N>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_vector_offset == 0) || ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
|
||||
size_t fbe_result = 4;
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
fbe_result += fbe_model.fbe_size() + fbe_model.fbe_extra();
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::offset() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return fbe_vector_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::size() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_vector_offset == 0) || ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
return fbe_vector_size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline FieldModel<T> FieldModelVector<T>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_vector_offset > 0) && ((_buffer.offset() + fbe_vector_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
[[maybe_unused]] uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
assert((index < fbe_vector_size) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
fbe_model.fbe_shift(index * fbe_model.fbe_size());
|
||||
return fbe_model;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline FieldModel<T> FieldModelVector<T>::resize(size_t size)
|
||||
{
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
|
||||
uint32_t fbe_vector_size = (uint32_t)(size * fbe_model.fbe_size());
|
||||
uint32_t fbe_vector_offset = (uint32_t)(_buffer.allocate(4 + fbe_vector_size) - _buffer.offset());
|
||||
assert(((fbe_vector_offset > 0) && ((_buffer.offset() + fbe_vector_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_vector_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset)) = (uint32_t)size;
|
||||
|
||||
memset((char*)(_buffer.data() + _buffer.offset() + fbe_vector_offset + 4), 0, fbe_vector_size);
|
||||
|
||||
return FieldModel<T>(_buffer, fbe_vector_offset + 4);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModelVector<T>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model.verify())
|
||||
return false;
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
values.reserve(fbe_vector_size);
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::list<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::set<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::list<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::set<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_map_offset == 0) || ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
|
||||
size_t fbe_result = 4;
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
fbe_result += fbe_model_key.fbe_size() + fbe_model_key.fbe_extra();
|
||||
fbe_model_key.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
fbe_result += fbe_model_value.fbe_size() + fbe_model_value.fbe_extra();
|
||||
fbe_model_value.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
}
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::offset() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return fbe_map_offset;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::size() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_map_offset == 0) || ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
return fbe_map_size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline std::pair<FieldModel<TKey>, FieldModel<TValue>> FieldModelMap<TKey, TValue>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_map_offset > 0) && ((_buffer.offset() + fbe_map_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
[[maybe_unused]] uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
assert((index < fbe_map_size) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
fbe_model_key.fbe_shift(index * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
fbe_model_value.fbe_shift(index * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
return std::make_pair(fbe_model_key, fbe_model_value);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline std::pair<FieldModel<TKey>, FieldModel<TValue>> FieldModelMap<TKey, TValue>::resize(size_t size)
|
||||
{
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_offset());
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_offset() + fbe_model_key.fbe_size());
|
||||
|
||||
uint32_t fbe_map_size = (uint32_t)(size * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
uint32_t fbe_map_offset = (uint32_t)(_buffer.allocate(4 + fbe_map_size) - _buffer.offset());
|
||||
assert(((fbe_map_offset > 0) && ((_buffer.offset() + fbe_map_offset + 4 + fbe_map_size) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_map_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset)) = (uint32_t)size;
|
||||
|
||||
memset((char*)(_buffer.data() + _buffer.offset() + fbe_map_offset + 4), 0, fbe_map_size);
|
||||
|
||||
return std::make_pair(FieldModel<TKey>(_buffer, fbe_map_offset + 4), FieldModel<TValue>(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size()));
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline bool FieldModelMap<TKey, TValue>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model_key.verify())
|
||||
return false;
|
||||
fbe_model_key.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
if (!fbe_model_value.verify())
|
||||
return false;
|
||||
fbe_model_value.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_map_size = size();
|
||||
if (fbe_map_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_map_size = size();
|
||||
if (fbe_map_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::set(const std::map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.first.set(value.first);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.set(value.second);
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::set(const std::unordered_map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.first.set(value.first);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.set(value.second);
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
|
|
@ -1,61 +1,65 @@
|
|||
#pragma once
|
||||
#include <iostream> //temporary
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <shared_mutex>
|
||||
#include "error_responses.hpp"
|
||||
#include "parallel-hashmap/parallel_hashmap/phmap.h"
|
||||
#include <parallel-hashmap/parallel_hashmap/phmap.h>
|
||||
#include "bank_resp.h"
|
||||
#include "user.h"
|
||||
|
||||
#if (CONSERVATIVE_DISK_SAVE && MAX_LOG_SIZE < 0) && !MULTI_THREADED
|
||||
#include "change_flag.h"
|
||||
#endif
|
||||
|
||||
class Bank
|
||||
{
|
||||
private:
|
||||
#if MULTI_THREADED
|
||||
phmap::parallel_flat_hash_map<
|
||||
std::string, User,
|
||||
phmap::priv::hash_default_hash<std::string>,
|
||||
xxHashStringGen,
|
||||
phmap::priv::hash_default_eq<std::string>,
|
||||
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
|
||||
4UL,
|
||||
std::mutex>
|
||||
users;
|
||||
#else
|
||||
phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> users;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief size_l should be grabbed if the operation MODIFIES the size (shared), this is so that when save claims unique
|
||||
*
|
||||
*/
|
||||
std::shared_mutex size_l;
|
||||
private:
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
ChangeFlag<false> save_flag;
|
||||
#else
|
||||
bool save_flag = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief send_funds_l should be grabbed if balances are being MODIFIED (shared) or if an operation needs to READ without the intermediary states that sendfunds has (unique)
|
||||
*
|
||||
*/
|
||||
std::shared_mutex send_funds_l;
|
||||
std::shared_mutex save_lock;
|
||||
|
||||
public:
|
||||
std::string admin_pass;
|
||||
std::string admin_account;
|
||||
|
||||
int_fast8_t AddUser(const std::string &name, const std::string &init_pass) noexcept;
|
||||
int_fast8_t AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept;
|
||||
size_t NumOfUsers() const noexcept;
|
||||
size_t NumOfLogs() const noexcept;
|
||||
size_t SumBal() const noexcept;
|
||||
|
||||
int_fast8_t DelUser(const std::string &name, const std::string &attempt) noexcept;
|
||||
int_fast8_t AdminDelUser(const std::string &name, const std::string &attempt) noexcept;
|
||||
BankResponse GetBal(const std::string &name) const noexcept;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
BankResponse GetLogs(const std::string &name) noexcept;
|
||||
#endif
|
||||
BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
|
||||
bool VerifyPassword(const std::string &name, const std::string_view &attempt) const noexcept;
|
||||
|
||||
int_fast8_t SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt) noexcept;
|
||||
void ChangePassword(const std::string &name, const std::string &new_pass) noexcept;
|
||||
BankResponse SetBal(const std::string &name, uint32_t amount) noexcept;
|
||||
BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
|
||||
bool Contains(const std::string &name) const noexcept;
|
||||
bool AdminVerifyAccount(const std::string &name) noexcept;
|
||||
|
||||
int_fast8_t Contains(const std::string &name) const noexcept;
|
||||
int_fast8_t AdminVerifyPass(const std::string &attempt) noexcept;
|
||||
BankResponse AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept;
|
||||
BankResponse DelUser(const std::string &name) noexcept;
|
||||
void DelSelf(const std::string &name) noexcept;
|
||||
|
||||
int_fast8_t SetBal(const std::string &name, const std::string &attempt, uint32_t amount) noexcept;
|
||||
int_fast64_t GetBal(const std::string &name) const noexcept;
|
||||
|
||||
int_fast8_t VerifyPassword(const std::string &name, const std::string &attempt) const noexcept;
|
||||
int_fast8_t ChangePassword(const std::string &name, const std::string &attempt, std::string &&new_pass) noexcept;
|
||||
|
||||
Json::Value GetLogs(const std::string &name, const std::string &attempt) noexcept;
|
||||
|
||||
void Save();
|
||||
|
||||
//NOT THREAD SAFE
|
||||
const char *Save();
|
||||
void Load();
|
||||
};
|
||||
|
||||
//TODO make branchless
|
||||
};
|
||||
78
include/bank_api.h
Normal file
78
include/bank_api.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
#include "str_intrusion.h"
|
||||
#include "json_filter.h"
|
||||
#include "user_filter.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
#define req_args const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback
|
||||
|
||||
class api : public HttpController<api, false>
|
||||
{
|
||||
Bank &bank;
|
||||
|
||||
public:
|
||||
api(Bank &b) noexcept;
|
||||
void JsonCpp(req_args) const;
|
||||
void Json(req_args) const;
|
||||
|
||||
#if API_VERSION >= 1
|
||||
void GetBal(req_args, const std::string &name) const;
|
||||
void GetLogs(req_args);
|
||||
void SendFunds(req_args) const;
|
||||
void VerifyPassword(req_args) const;
|
||||
|
||||
void ChangePassword(req_args) const;
|
||||
void AdminChangePassword(req_args) const;
|
||||
void SetBal(req_args) const;
|
||||
void ImpactBal(req_args) const;
|
||||
|
||||
void Help(req_args) const;
|
||||
void Close(req_args) const;
|
||||
void Contains(req_args, const std::string &name) const;
|
||||
void AdminVerifyAccount(req_args) const;
|
||||
void ApiProperties(req_args) const;
|
||||
|
||||
void AddUser(req_args) const;
|
||||
void AdminAddUser(req_args) const;
|
||||
void DelSelf(req_args) const;
|
||||
void AdminDelUser(req_args) const;
|
||||
|
||||
#endif
|
||||
|
||||
METHOD_LIST_BEGIN
|
||||
|
||||
#if API_VERSION >= 1
|
||||
//Usage
|
||||
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
|
||||
#if MAX_LOG_SIZE > 0
|
||||
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
|
||||
#else
|
||||
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
|
||||
#endif
|
||||
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](32 bits)
|
||||
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");
|
||||
|
||||
//Meta Usage
|
||||
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
|
||||
METHOD_ADD(api::AdminChangePassword, "/v1/admin/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["pass"](string)
|
||||
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](32 bits)
|
||||
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](32 bits)
|
||||
|
||||
//System Usage
|
||||
METHOD_ADD(api::Help, "/v1/help", Get, Options);
|
||||
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options, "JsonFilter<false>");
|
||||
METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
|
||||
|
||||
//User Managment
|
||||
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string)
|
||||
METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) ["amount"](32 bits) ["pass"](string)
|
||||
METHOD_ADD(api::DelSelf, "/v1/user/delete", Delete, Options, "UserFilter<true, false>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::AdminDelUser, "/v1/admin/user/delete", Delete, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string)
|
||||
#endif
|
||||
METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
|
||||
|
||||
METHOD_LIST_END
|
||||
};
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
#include "bank.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
#define req_args const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback
|
||||
|
||||
class BankF : public HttpController<BankF, false>
|
||||
{
|
||||
Bank &bank;
|
||||
|
||||
public:
|
||||
BankF(Bank *b);
|
||||
void Help(req_args) const;
|
||||
void Ping(req_args) const;
|
||||
void Close(req_args) const;
|
||||
void AddUser(req_args, const std::string &name) const;
|
||||
void AdminAddUser(req_args, std::string &&name, uint32_t init_bal) const;
|
||||
void DelUser(req_args, const std::string &name) const;
|
||||
void AdminDelUser(req_args, const std::string &name) const;
|
||||
void SendFunds(req_args, const std::string name, const std::string to, uint32_t amount) const;
|
||||
void ChangePassword(req_args, const std::string &name) const;
|
||||
void Contains(req_args, const std::string &name) const;
|
||||
void GetBal(req_args, const std::string &name) const;
|
||||
void VerifyPassword(req_args, const std::string &name) const;
|
||||
void SetBal(req_args, const std::string &name, uint32_t amount) const;
|
||||
void AdminVerifyPass(req_args);
|
||||
void GetLog(req_args, const std::string &name);
|
||||
|
||||
METHOD_LIST_BEGIN
|
||||
|
||||
//Usage
|
||||
METHOD_ADD(BankF::GetBal, "/{name}/bal", Get, Options);
|
||||
METHOD_ADD(BankF::GetLog, "/{name}/log", Get, Options);
|
||||
METHOD_ADD(BankF::SendFunds, "/{name}/send/{to}?amount={amount}", Post, Options);
|
||||
METHOD_ADD(BankF::VerifyPassword, "/{name}/pass/verify", Get, Options);
|
||||
|
||||
//Meta Usage
|
||||
METHOD_ADD(BankF::ChangePassword, "/{name}/pass/change", Patch, Options);
|
||||
METHOD_ADD(BankF::SetBal, "/admin/{name}/bal?amount={amount}", Patch, Options);
|
||||
|
||||
//System Usage
|
||||
METHOD_ADD(BankF::Help, "/help", Get, Options);
|
||||
METHOD_ADD(BankF::Ping, "/ping", Get, Options);
|
||||
METHOD_ADD(BankF::Close, "/admin/close", Post, Options);
|
||||
METHOD_ADD(BankF::Contains, "/contains/{name}", Get, Options);
|
||||
METHOD_ADD(BankF::AdminVerifyPass, "/admin/verify", Get, Options);
|
||||
|
||||
//User Managment
|
||||
METHOD_ADD(BankF::AddUser, "/user/{name}", Post, Options);
|
||||
METHOD_ADD(BankF::AdminAddUser, "/admin/user/{name}?init_bal={init_bal}", Post, Options);
|
||||
METHOD_ADD(BankF::DelUser, "/user/{name}", Delete, Options);
|
||||
METHOD_ADD(BankF::AdminDelUser, "/admin/user/{name}", Delete, Options);
|
||||
|
||||
METHOD_LIST_END
|
||||
};
|
||||
12
include/bank_resp.h
Normal file
12
include/bank_resp.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <../src/HttpResponseImpl.h>
|
||||
#include <../src/HttpAppFrameworkImpl.h>
|
||||
|
||||
using BankResponse = std::pair<drogon::HttpStatusCode, std::optional<std::string>>;
|
||||
|
||||
template <>
|
||||
drogon::HttpResponsePtr drogon::toResponse(BankResponse &&data);
|
||||
17
include/change_flag.h
Normal file
17
include/change_flag.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
template <bool init>
|
||||
class ChangeFlag
|
||||
{
|
||||
private:
|
||||
std::atomic<bool> change_flag = init; //if true changes have been made
|
||||
|
||||
public:
|
||||
ChangeFlag() noexcept;
|
||||
ChangeFlag(ChangeFlag &&) noexcept;
|
||||
|
||||
void SetChangesOn() noexcept;
|
||||
void SetChangesOff() noexcept;
|
||||
bool GetChangeState() const noexcept;
|
||||
};
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// Setting both values to 0 does not compile logging
|
||||
constexpr unsigned max_log_size = 100;
|
||||
constexpr unsigned pre_log_size = 10;
|
||||
|
||||
constexpr unsigned max_name_size = 50;
|
||||
|
||||
constexpr const char *users_location = "../users.json";
|
||||
constexpr const char *config_location = "../config.json";
|
||||
|
||||
//returns money to an account on deletion
|
||||
constexpr bool return_on_del = false;
|
||||
constexpr const char *return_account = "";
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
enum ErrorResponse
|
||||
{
|
||||
UserNotFound = -1,
|
||||
WrongPassword = -2,
|
||||
InvalidRequest = -3,
|
||||
NameTooLong = -4,
|
||||
UserAlreadyExists = -5,
|
||||
InsufficientFunds = -6,
|
||||
};
|
||||
16
include/json_filter.h
Normal file
16
include/json_filter.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include "bank_resp.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
template <bool check_content_type>
|
||||
class JsonFilter : public HttpFilter<JsonFilter<check_content_type>, false>
|
||||
{
|
||||
public:
|
||||
JsonFilter();
|
||||
|
||||
virtual void doFilter(const HttpRequestPtr &,
|
||||
FilterCallback &&,
|
||||
FilterChainCallback &&) override;
|
||||
};
|
||||
|
|
@ -1,13 +1,23 @@
|
|||
#pragma once
|
||||
#include <json/json.h>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include "consts.hpp"
|
||||
#include <json/json.h> // to be removed later
|
||||
#include <deque>
|
||||
#include "ccash_config.hpp"
|
||||
#include "change_flag.h"
|
||||
#include "transaction.h"
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct Log
|
||||
{
|
||||
std::vector<Transaction> data;
|
||||
void AddTrans(Transaction &&t);
|
||||
Json::Value Serialize() const;
|
||||
private:
|
||||
ChangeFlag<true> log_flag;
|
||||
std::string log_snapshot = "null";
|
||||
|
||||
public:
|
||||
std::deque<Transaction> data;
|
||||
|
||||
std::string GetLogs() noexcept;
|
||||
void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept;
|
||||
Json::Value Serialize() const; // to be removed later
|
||||
};
|
||||
|
|
|
|||
23863
include/simdjson.h
Normal file
23863
include/simdjson.h
Normal file
File diff suppressed because it is too large
Load diff
10
include/str_intrusion.h
Normal file
10
include/str_intrusion.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
struct StrFromSV_Wrapper
|
||||
{
|
||||
std::string str;
|
||||
StrFromSV_Wrapper() noexcept;
|
||||
StrFromSV_Wrapper(std::string_view sv) noexcept;
|
||||
~StrFromSV_Wrapper() noexcept;
|
||||
};
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
std::string from = "", to = "";
|
||||
uint32_t amount = 0;
|
||||
uint64_t time = 0;
|
||||
time_t time = 0;
|
||||
|
||||
Transaction();
|
||||
Transaction(std::string from_str, std::string to_str, uint32_t amount, uint64_t time);
|
||||
Transaction(std::string from_str, std::string to_str, uint32_t amount);
|
||||
Transaction() noexcept;
|
||||
Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time) noexcept;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
#pragma once
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <xxhash.h>
|
||||
#include <json/json.h> //to be removed later
|
||||
#include "xxhash_str.h"
|
||||
#include "bank_dom_final_models.h"
|
||||
#include "log.h"
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32_t balance = 0;
|
||||
uint64_t password;
|
||||
uint32_t balance;
|
||||
XXH64_hash_t password;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
Log log;
|
||||
#endif
|
||||
|
||||
User(const std::string &init_pass);
|
||||
User(uint32_t init_bal, const std::string &init_pass);
|
||||
User(uint32_t init_bal, uint64_t init_pass);
|
||||
User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j);
|
||||
User(uint32_t init_bal, const std::string &init_pass) noexcept;
|
||||
User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
User(uint32_t init_bal, XXH64_hash_t init_pass, const Json::Value &log_j) noexcept;
|
||||
User(const bank_dom::User &u) noexcept;
|
||||
bank_dom::User Encode() const noexcept;
|
||||
#endif
|
||||
|
||||
Json::Value Serialize() const;
|
||||
Json::Value Serialize() const; //to be removed later
|
||||
};
|
||||
|
|
|
|||
21
include/user_filter.h
Normal file
21
include/user_filter.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <libbase64.h>
|
||||
#include "str_intrusion.h"
|
||||
#include "bank.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
template <bool set_body_flag, bool require_admin>
|
||||
class UserFilter : public HttpFilter<UserFilter<set_body_flag, require_admin>, false>
|
||||
{
|
||||
private:
|
||||
Bank &bank;
|
||||
|
||||
public:
|
||||
UserFilter(Bank &b);
|
||||
|
||||
virtual void doFilter(const HttpRequestPtr &,
|
||||
FilterCallback &&,
|
||||
FilterChainCallback &&) override;
|
||||
};
|
||||
|
|
@ -266,7 +266,7 @@ extern "C" {
|
|||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 8
|
||||
#define XXH_VERSION_RELEASE 0
|
||||
#define XXH_VERSION_RELEASE 1
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
|
||||
/*!
|
||||
|
|
@ -275,7 +275,7 @@ extern "C" {
|
|||
* This is only useful when xxHash is compiled as a shared library, as it is
|
||||
* independent of the version defined in the header.
|
||||
*
|
||||
* @return `XXH_VERSION_NUMBER` as of when the function was compiled.
|
||||
* @return `XXH_VERSION_NUMBER` as of when the libray was compiled.
|
||||
*/
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
|
@ -3341,7 +3341,7 @@ XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_
|
|||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
XXH_ASSERT(secret != NULL);
|
||||
XXH_ASSERT(8 <= len && len <= 16);
|
||||
XXH_ASSERT(9 <= len && len <= 16);
|
||||
{ xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed;
|
||||
xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed;
|
||||
xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1;
|
||||
|
|
|
|||
9
include/xxhash_str.h
Normal file
9
include/xxhash_str.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "xxhash.h"
|
||||
|
||||
struct xxHashStringGen
|
||||
{
|
||||
XXH64_hash_t operator()(const std::string &str) const noexcept;
|
||||
XXH64_hash_t operator()(const std::string_view &str) const noexcept;
|
||||
};
|
||||
150
main.cpp
150
main.cpp
|
|
@ -3,13 +3,17 @@
|
|||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "bank_f.h"
|
||||
#include "bank_api.h"
|
||||
|
||||
//sig handling headers
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//threads of cpu
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace drogon;
|
||||
|
||||
|
|
@ -17,63 +21,111 @@ static Bank bank;
|
|||
|
||||
void SaveSig(int s)
|
||||
{
|
||||
bank.Save();
|
||||
std::cout << "\nSaving on close...\n";
|
||||
std::cout << "\nSaving on close...\n"
|
||||
<< bank.Save();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static_assert(bool(max_log_size) == bool(pre_log_size), "You must either utilize both or neither logging variables.\n");
|
||||
static_assert(max_log_size >= pre_log_size, "The maximum log size must be larger than or equal to the amount preallocated.\n");
|
||||
static_assert(!max_log_size || !(max_log_size % pre_log_size), "The maximum log size must be divisible by the preallocation size.\n");
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
std::cerr << "Usage: sudo ./bank <admin password> <saving frequency in minutes> <threads>\n";
|
||||
return 0;
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
std::cerr << "ERROR: CCash MUST be ran as root\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Loading users from users.json
|
||||
bank.Load();
|
||||
|
||||
//Sig handling
|
||||
struct sigaction sigIntHandler;
|
||||
|
||||
sigIntHandler.sa_handler = SaveSig;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
||||
|
||||
//Admin Password
|
||||
bank.admin_pass = argv[1];
|
||||
|
||||
//Auto Saving
|
||||
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
|
||||
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
|
||||
{
|
||||
std::thread([saving_freq]() {
|
||||
while (1)
|
||||
if (argc == 1)
|
||||
{
|
||||
std::ofstream users_save(users_location, std::ios::out | std::ios::binary);
|
||||
if (users_save.is_open())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
bank.Save();
|
||||
std::cout << "Saving " << duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() << '\n';
|
||||
uint8_t temp[16]{16, 0, 0, 0, 4};
|
||||
users_save.write((char *)temp, 16);
|
||||
users_save.close();
|
||||
std::cout << "User save file generated\nUsage: sudo ./bank <admin account> <saving frequency in minutes>\n";
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "File cannot be created\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc != 3)
|
||||
{
|
||||
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes>\n";
|
||||
return 0;
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
std::cerr << "ERROR: CCash MUST be ran as root\n";
|
||||
return 0;
|
||||
}
|
||||
std::cout
|
||||
<< "\nAPI Version : " << API_VERSION
|
||||
<< "\n\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
|
||||
<< "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.1 : " << (__builtin_cpu_supports("sse4.1") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.2 : " << (__builtin_cpu_supports("sse4.2") ? "enabled" : "disabled")
|
||||
#if MULTI_THREADED
|
||||
<< "\n\nThreads : " << get_nprocs() + 1
|
||||
<< "\nMulti threading : enabled";
|
||||
#else
|
||||
<< "\n\nThreads : " << 2
|
||||
<< "\nMulti threading : disabled";
|
||||
#endif
|
||||
|
||||
auto API = std::make_shared<BankF>(&bank);
|
||||
app().registerPostHandlingAdvice(
|
||||
[](const drogon::HttpRequestPtr &req, const drogon::HttpResponsePtr &resp) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", "*");
|
||||
});
|
||||
app().loadConfigFile(config_location).registerController(API).setThreadNum(std::stoul(std::string(argv[3]))).run();
|
||||
//Loading users from users.json
|
||||
bank.Load();
|
||||
size_t num_of_logs = bank.NumOfLogs();
|
||||
size_t num_of_users = bank.NumOfUsers();
|
||||
std::cout << "\n\nLoaded " << num_of_users << " Users ~" << (float)(sizeof(User) * num_of_users) / 1048576 << "Mb"
|
||||
<< "\nLoaded " << num_of_logs << " Logs ~" << (float)(num_of_logs * (90 + 80 + (max_name_size * 2))) / 1048576 << "Mb" //90:string representation(heap), sizeof(Transaction), max_name_size*2:filled to&from(heap)
|
||||
<< "\nLoaded " << bank.SumBal() << " CSH"
|
||||
<< std::endl; //flushing before EventLoop
|
||||
|
||||
//Sig handling
|
||||
struct sigaction sigIntHandler;
|
||||
|
||||
sigIntHandler.sa_handler = SaveSig;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
||||
|
||||
//Admin account
|
||||
bank.admin_account = argv[1];
|
||||
|
||||
//Auto Saving
|
||||
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
|
||||
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
|
||||
{
|
||||
std::thread([saving_freq]() {
|
||||
while (1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
std::cout << "Saving " << std::time(0) << "...\n"
|
||||
<< bank.Save();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
} //destroying setup variables
|
||||
static auto API = std::make_shared<api>(bank);
|
||||
static auto user_filter_default = std::make_shared<UserFilter<true, false>>(bank);
|
||||
static auto user_filter_sparse = std::make_shared<UserFilter<false, false>>(bank);
|
||||
static auto admin_filter = std::make_shared<UserFilter<false, true>>(bank);
|
||||
static auto json_resp_and_req_filter = std::make_shared<JsonFilter<true>>();
|
||||
static auto json_resp_filter = std::make_shared<JsonFilter<false>>();
|
||||
|
||||
app()
|
||||
.loadConfigFile(config_location)
|
||||
.registerFilter(user_filter_default)
|
||||
.registerFilter(user_filter_sparse)
|
||||
.registerFilter(admin_filter)
|
||||
.registerFilter(json_resp_and_req_filter)
|
||||
.registerFilter(json_resp_filter)
|
||||
.registerController(API)
|
||||
#if MULTI_THREADED
|
||||
.setThreadNum(get_nprocs())
|
||||
#endif
|
||||
.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
580
src/bank.cpp
580
src/bank.cpp
|
|
@ -1,283 +1,377 @@
|
|||
#include "bank.h"
|
||||
|
||||
int_fast8_t Bank::AddUser(const std::string &name, const std::string &init_pass) noexcept
|
||||
using namespace drogon;
|
||||
|
||||
__attribute__((always_inline)) inline bool ValidUsername(const std::string &name) noexcept
|
||||
{
|
||||
if (name.size() > max_name_size)
|
||||
if (name.size() < min_name_size || name.size() > max_name_size)
|
||||
{
|
||||
return ErrorResponse::NameTooLong;
|
||||
return false;
|
||||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (c == ' ')
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return ErrorResponse::InvalidRequest;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, init_pass))
|
||||
? true
|
||||
: ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
}
|
||||
int_fast8_t Bank::AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept
|
||||
{
|
||||
if (name.size() > max_name_size)
|
||||
{
|
||||
return ErrorResponse::NameTooLong;
|
||||
}
|
||||
if (admin_pass != attempt)
|
||||
{
|
||||
return ErrorResponse::WrongPassword;
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass)))
|
||||
? true
|
||||
: ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
int_fast8_t Bank::DelUser(const std::string &name, const std::string &attempt) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
bool state = false;
|
||||
if (users.erase_if(name, [&state, &attempt](User &u) { return state = (XXH3_64bits(attempt.data(), attempt.size()) == u.password); }))
|
||||
{
|
||||
return (state) ? true : ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
}
|
||||
int_fast8_t Bank::AdminDelUser(const std::string &name, const std::string &attempt) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
bool state = false;
|
||||
if (users.erase_if(name, [this, &state, &attempt](const User &) { return state = (admin_pass == attempt); }))
|
||||
{
|
||||
return (state) ? true : ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int_fast8_t Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt) noexcept
|
||||
{
|
||||
//cant send money to self, from self or amount is 0
|
||||
if (a_name == b_name || !amount)
|
||||
{
|
||||
return ErrorResponse::InvalidRequest;
|
||||
}
|
||||
//as first modify_if checks a_name and grabs unique lock
|
||||
if (Contains(b_name) != true)
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::NumOfUsers() const noexcept { return users.size(); }
|
||||
|
||||
int_fast8_t state = false;
|
||||
if constexpr (max_log_size > 0)
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::NumOfLogs() const noexcept
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
size_t res = 0;
|
||||
for (const auto &u : users)
|
||||
{
|
||||
Transaction temp(a_name, b_name, amount);
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l};
|
||||
users.modify_if(a_name, [&temp, &state, amount, &attempt](User &a) {
|
||||
//if A can afford it and A's password matches attempt
|
||||
if (a.balance < amount)
|
||||
{
|
||||
state = ErrorResponse::InsufficientFunds;
|
||||
}
|
||||
else if (a.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
state = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
a.log.AddTrans(Transaction(temp));
|
||||
state = true;
|
||||
}
|
||||
});
|
||||
if (state > 0)
|
||||
{
|
||||
users.modify_if(b_name, [&a_name, &b_name, &temp, amount](User &b) {
|
||||
b.balance += amount;
|
||||
b.log.AddTrans(std::move(temp));
|
||||
});
|
||||
}
|
||||
return state;
|
||||
res += u.second.log.data.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l};
|
||||
users.modify_if(a_name, [&state, amount, &attempt](User &a) {
|
||||
//if A can afford it and A's password matches attempt
|
||||
if (a.balance < amount)
|
||||
{
|
||||
state = ErrorResponse::InsufficientFunds;
|
||||
}
|
||||
else if (a.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
|
||||
state = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
state = true;
|
||||
}
|
||||
});
|
||||
if (state > 0)
|
||||
{
|
||||
users.modify_if(b_name, [&a_name, &b_name, amount](User &b) {
|
||||
b.balance += amount;
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
int_fast8_t Bank::Contains(const std::string &name) const noexcept
|
||||
{
|
||||
return (users.contains(name)) ? true : ErrorResponse::UserNotFound;
|
||||
}
|
||||
int_fast8_t Bank::AdminVerifyPass(const std::string &attempt) noexcept
|
||||
{
|
||||
return (admin_pass == attempt) ? true : ErrorResponse::WrongPassword;
|
||||
}
|
||||
|
||||
int_fast8_t Bank::SetBal(const std::string &name, const std::string &attempt, uint32_t amount) noexcept
|
||||
{
|
||||
if (admin_pass != attempt)
|
||||
{
|
||||
return ErrorResponse::WrongPassword;
|
||||
}
|
||||
|
||||
return (users.modify_if(name, [amount](User &u) {
|
||||
u.balance = amount;
|
||||
}))
|
||||
? true
|
||||
: ErrorResponse::UserNotFound;
|
||||
}
|
||||
int_fast64_t Bank::GetBal(const std::string &name) const noexcept
|
||||
{
|
||||
int_fast64_t res = ErrorResponse::UserNotFound;
|
||||
users.if_contains(name, [&res](const User &u) {
|
||||
res = u.balance;
|
||||
});
|
||||
return res;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int_fast8_t Bank::VerifyPassword(const std::string &name, const std::string &attempt) const noexcept
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::SumBal() const noexcept
|
||||
{
|
||||
int_fast8_t res = ErrorResponse::UserNotFound;
|
||||
users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
res = (u.password == XXH3_64bits(attempt.data(), attempt.size())) ? true : ErrorResponse::WrongPassword;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
int_fast8_t Bank::ChangePassword(const std::string &name, const std::string &attempt, std::string &&new_pass) noexcept
|
||||
{
|
||||
int_fast8_t res = ErrorResponse::UserNotFound;
|
||||
users.modify_if(name, [&res, &attempt, &new_pass](User &u) {
|
||||
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
res = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = true;
|
||||
u.password = XXH3_64bits(new_pass.data(), new_pass.size());
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
Json::Value Bank::GetLogs(const std::string &name, const std::string &attempt) noexcept
|
||||
{
|
||||
Json::Value res;
|
||||
if (!users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
res = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = u.log.data.size(); i > 0; --i)
|
||||
{
|
||||
res[i - 1]["to"] = u.log.data[u.log.data.size() - i].to;
|
||||
res[i - 1]["from"] = u.log.data[u.log.data.size() - i].from;
|
||||
res[i - 1]["amount"] = (Json::UInt)u.log.data[u.log.data.size() - i].amount;
|
||||
res[i - 1]["time"] = (Json::UInt64)u.log.data[u.log.data.size() - i].time;
|
||||
}
|
||||
}
|
||||
}))
|
||||
size_t res = 0;
|
||||
for (const auto &u : users)
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
res += u.second.balance;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Bank::Save()
|
||||
BankResponse Bank::GetBal(const std::string &name) const noexcept
|
||||
{
|
||||
Json::Value temp;
|
||||
|
||||
//loading info into json temp
|
||||
uint32_t res = 0;
|
||||
if (!ValidUsername(name) || !users.if_contains(name, [&res](const User &u)
|
||||
{ res = u.balance; }))
|
||||
{
|
||||
std::scoped_lock<std::shared_mutex, std::shared_mutex> lock{size_l, send_funds_l};
|
||||
for (const auto &u : users)
|
||||
{
|
||||
//we know it contains this key but we call this func to grab mutex
|
||||
users.if_contains(u.first, [&temp, &u](const User &u_val) {
|
||||
temp[u.first] = u_val.Serialize();
|
||||
});
|
||||
}
|
||||
}
|
||||
if (temp.isNull())
|
||||
{
|
||||
throw std::invalid_argument("Saving Failed\n");
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ofstream user_save(users_location);
|
||||
Json::StreamWriterBuilder builder;
|
||||
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
|
||||
writer->write(temp, &user_save);
|
||||
user_save.close();
|
||||
return {k200OK, std::to_string(res)};
|
||||
}
|
||||
}
|
||||
#if MAX_LOG_SIZE > 0
|
||||
BankResponse Bank::GetLogs(const std::string &name) noexcept
|
||||
{
|
||||
BankResponse res;
|
||||
if (!users.modify_if(name, [&res](User &u)
|
||||
{ res = {k200OK, u.log.GetLogs()}; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept
|
||||
{
|
||||
if (!amount)
|
||||
{
|
||||
return {k400BadRequest, "\"Amount cannot be 0\""};
|
||||
}
|
||||
if (a_name == b_name)
|
||||
{
|
||||
return {k400BadRequest, "\"Names cannot match\""};
|
||||
}
|
||||
if (!Contains(b_name))
|
||||
{
|
||||
return {k404NotFound, "\"Reciever does not exist\""};
|
||||
}
|
||||
|
||||
BankResponse res;
|
||||
std::shared_lock<std::shared_mutex> lock{save_lock};
|
||||
#if MAX_LOG_SIZE > 0
|
||||
time_t current_time = time(NULL);
|
||||
#endif
|
||||
if (!users.modify_if(a_name, [current_time, &a_name, &b_name, &res, amount](User &a)
|
||||
{
|
||||
//if A can afford it
|
||||
if (a.balance < amount)
|
||||
{
|
||||
res = {k400BadRequest, "\"Insufficient funds\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
a.log.AddTrans(a_name, b_name, amount, current_time);
|
||||
#endif
|
||||
res = {k200OK, std::to_string(a.balance)};
|
||||
}
|
||||
}))
|
||||
{
|
||||
return {k404NotFound, "\"Sender does not exist\""};
|
||||
}
|
||||
if (res.first == k200OK)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b)
|
||||
{
|
||||
b.balance += amount;
|
||||
b.log.AddTrans(a_name, b_name, amount, current_time);
|
||||
});
|
||||
#else
|
||||
users.modify_if(b_name, [amount](User &b)
|
||||
{ b.balance += amount; });
|
||||
#endif
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
bool Bank::VerifyPassword(const std::string &name, const std::string_view &attempt) const noexcept
|
||||
{
|
||||
bool res = false;
|
||||
users.if_contains(name, [&res, &attempt](const User &u)
|
||||
{ res = (u.password == xxHashStringGen{}(attempt)); });
|
||||
return res;
|
||||
}
|
||||
|
||||
void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
users.modify_if(name, [&new_pass](User &u)
|
||||
{ u.password = xxHashStringGen{}(new_pass); });
|
||||
}
|
||||
BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept
|
||||
{
|
||||
if (ValidUsername(name) && users.modify_if(name, [amount](User &u)
|
||||
{ u.balance = amount; }))
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
return {k204NoContent, std::nullopt}; //returns new balance
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept
|
||||
{
|
||||
if (amount == 0)
|
||||
{
|
||||
return {k400BadRequest, "\"Amount cannot be 0\""};
|
||||
}
|
||||
uint32_t balance;
|
||||
if (ValidUsername(name) && users.modify_if(name, [&balance, amount](User &u)
|
||||
{ balance = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); }))
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
return {k200OK, std::to_string(balance)}; //may return new balance
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
bool Bank::Contains(const std::string &name) const noexcept
|
||||
{
|
||||
return ValidUsername(name) && users.contains(name);
|
||||
}
|
||||
bool Bank::AdminVerifyAccount(const std::string &name) noexcept
|
||||
{
|
||||
return (name == admin_account);
|
||||
}
|
||||
BankResponse Bank::AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept
|
||||
{
|
||||
if (!ValidUsername(name))
|
||||
{
|
||||
return {k400BadRequest, "\"Invalid Username\""};
|
||||
}
|
||||
std::shared_lock<std::shared_mutex> lock{save_lock};
|
||||
if (users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, init_pass))
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
return {k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k409Conflict, "\"User already exists\""};
|
||||
}
|
||||
}
|
||||
BankResponse Bank::DelUser(const std::string &name) noexcept
|
||||
{
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (users.if_contains(name, [&bal](const User &u)
|
||||
{ bal = u.balance; }) &&
|
||||
bal)
|
||||
{
|
||||
users.modify_if(return_account, [bal](User & u))
|
||||
{
|
||||
u.balance += bal;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::shared_lock<std::shared_mutex> lock{save_lock};
|
||||
if (ValidUsername(name) && users.erase(name))
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
return {k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
//assumes we know name exists, unlike DelUser
|
||||
void Bank::DelSelf(const std::string &name) noexcept
|
||||
{
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (users.if_contains(name, [&bal](const User &u)
|
||||
{ bal = u.balance; }) &&
|
||||
bal)
|
||||
{
|
||||
users.modify_if(return_account, [bal](User & u))
|
||||
{
|
||||
u.balance += bal;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOn();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
#endif
|
||||
std::shared_lock<std::shared_mutex> lock{save_lock};
|
||||
users.erase(name);
|
||||
}
|
||||
//ONLY EVER BEING CALLED BY SAVE THREAD OR C-INTERUPT
|
||||
const char *Bank::Save()
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
if (
|
||||
#if MULTI_THREADED
|
||||
save_flag.GetChangeState()
|
||||
#else
|
||||
save_flag
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#endif
|
||||
std::ofstream users_save(users_location, std::ios::out | std::ios::binary);
|
||||
if (!users_save.is_open())
|
||||
{
|
||||
throw std::invalid_argument("Cannot access saving file\n");
|
||||
}
|
||||
bank_dom::Global users_copy;
|
||||
users_copy.users.reserve(users.size());
|
||||
users_copy.keys.reserve(users.size());
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock{save_lock};
|
||||
for (const auto &u : users)
|
||||
{
|
||||
//we know it contains this key but we call this func to grab mutex
|
||||
users.if_contains(u.first, [&users_copy, &u](const User &u_val)
|
||||
{
|
||||
users_copy.users.emplace_back(u_val.Encode());
|
||||
users_copy.keys.emplace_back(u.first);
|
||||
});
|
||||
}
|
||||
}
|
||||
FBE::bank_dom::GlobalFinalModel writer;
|
||||
writer.serialize(users_copy);
|
||||
if (!writer.verify())
|
||||
{
|
||||
throw std::invalid_argument("Data is corrupted\n");
|
||||
}
|
||||
const FBE::FBEBuffer &write_buffer = writer.buffer();
|
||||
users_save.write((char *)write_buffer.data(), write_buffer.size());
|
||||
users_save.close();
|
||||
if (!users_save.good())
|
||||
{
|
||||
throw std::invalid_argument("Error occurred at writing\n");
|
||||
}
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#if MULTI_THREADED
|
||||
save_flag.SetChangesOff();
|
||||
#else
|
||||
save_flag = true;
|
||||
#endif
|
||||
return " to disk...\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
return " no changes...\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
|
||||
void Bank::Load()
|
||||
{
|
||||
Json::CharReaderBuilder builder;
|
||||
|
||||
Json::Value temp;
|
||||
std::ifstream user_save(users_location);
|
||||
builder["collectComments"] = true;
|
||||
JSONCPP_STRING errs;
|
||||
if (!parseFromStream(builder, user_save, &temp, &errs))
|
||||
std::ifstream users_load(users_location, std::ios::out | std::ios::binary);
|
||||
if (!users_load.is_open())
|
||||
{
|
||||
std::cerr << errs << '\n';
|
||||
user_save.close();
|
||||
throw std::invalid_argument("Parsing Failed\n");
|
||||
throw std::invalid_argument("Cannot find save file, to generate a new one run ./bank\n");
|
||||
}
|
||||
else
|
||||
|
||||
uint32_t buffer_size;
|
||||
users_load.read((char *)&buffer_size, 4); //reading first 32 bits for size
|
||||
FBE::bank_dom::GlobalFinalModel reader; //declaring model
|
||||
reader.resize(buffer_size); //allocating new memory
|
||||
users_load.read((char *)reader.buffer().data() + 4, buffer_size - 4); //reading rest of file
|
||||
memcpy((char *)reader.buffer().data(), &buffer_size, 4); //copying first 32 bits back
|
||||
|
||||
if (!reader.verify())
|
||||
{
|
||||
user_save.close();
|
||||
for (const auto &u : temp.getMemberNames())
|
||||
{
|
||||
if constexpr (max_log_size > 0)
|
||||
{
|
||||
users.try_emplace(u, temp[u]["balance"].asUInt(), std::move(temp[u]["password"].asUInt64()), temp[u]["log"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
users.try_emplace(u, temp[u]["balance"].asUInt(), std::move(temp[u]["password"].asUInt64()));
|
||||
}
|
||||
}
|
||||
throw std::invalid_argument("Data is corrupted\n");
|
||||
}
|
||||
bank_dom::Global users_global;
|
||||
reader.deserialize(users_global);
|
||||
|
||||
for (size_t i = 0; i < users_global.users.size(); ++i)
|
||||
{
|
||||
users.try_emplace(users_global.keys[i], users_global.users[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
310
src/bank_api.cpp
Normal file
310
src/bank_api.cpp
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
#include "bank_api.h"
|
||||
|
||||
//all my homies hate jsoncpp
|
||||
|
||||
#define CACHE_FOREVER resp->setExpiredTime(0)
|
||||
|
||||
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
|
||||
|
||||
static thread_local ondemand::parser parser;
|
||||
#define SIMD_JSON_GEN \
|
||||
static thread_local simdjson::padded_string input(req->getBody()); \
|
||||
static thread_local auto doc = parser.iterate(input)
|
||||
|
||||
#define RESPONSE_PARSE(R) \
|
||||
static thread_local auto resp = HttpResponse::newCustomHttpResponse(R); \
|
||||
CORS; \
|
||||
callback(resp)
|
||||
|
||||
#define RESPOND_TRUE \
|
||||
static thread_local auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k204NoContent, std::nullopt}); \
|
||||
CORS; \
|
||||
CACHE_FOREVER; \
|
||||
callback(resp)
|
||||
|
||||
#define NAME_PARAM req->getParameter("name")
|
||||
|
||||
api::api(Bank &b) noexcept : bank(b)
|
||||
{
|
||||
}
|
||||
|
||||
#if API_VERSION >= 1
|
||||
|
||||
//Usage
|
||||
void api::GetBal(req_args, const std::string &name) const
|
||||
{
|
||||
RESPONSE_PARSE(bank.GetBal(name));
|
||||
}
|
||||
void api::GetLogs(req_args)
|
||||
{
|
||||
if constexpr (MAX_LOG_SIZE > 0)
|
||||
{
|
||||
RESPONSE_PARSE(bank.GetLogs(NAME_PARAM));
|
||||
}
|
||||
else
|
||||
{
|
||||
static thread_local auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
}
|
||||
void api::SendFunds(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto amount = doc.find_field("amount").get_uint64();
|
||||
if (name.error() || amount.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = bank.SendFunds(NAME_PARAM, name_val.str, amount.value());
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::VerifyPassword(req_args) const { RESPOND_TRUE; }
|
||||
|
||||
//Meta Usage
|
||||
void api::ChangePassword(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pass = doc.find_field("pass").get_string();
|
||||
if (pass.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
bank.ChangePassword(NAME_PARAM, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::AdminChangePassword(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto pass = doc.find_field("pass").get_string();
|
||||
if (name.error() || pass.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
if (bank.Contains(name_val.str))
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
bank.ChangePassword(name_val.str, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = BankResponse{k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::SetBal(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto amount = doc.find_field("amount").get_uint64();
|
||||
if (name.error() || amount.error())
|
||||
{
|
||||
res = BankResponse(k400BadRequest, "\"Missing JSON arg(s)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = bank.SetBal(name_val.str, amount.value());
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::ImpactBal(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto amount = doc.find_field("amount").get_int64();
|
||||
if (name.error() || amount.error())
|
||||
{
|
||||
res = BankResponse(k400BadRequest, "\"Missing JSON arg(s)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = bank.ImpactBal(name_val.str, amount.value());
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
|
||||
//System Usage
|
||||
void api::Help(req_args) const
|
||||
{
|
||||
static thread_local auto resp = HttpResponse::newRedirectionResponse("https://github.com/EntireTwix/CCash/blob/README.md", k301MovedPermanently);
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
void api::Close(req_args) const
|
||||
{
|
||||
bank.Save();
|
||||
RESPOND_TRUE; //filter handles admin creds
|
||||
app().quit();
|
||||
}
|
||||
void api::Contains(req_args, const std::string &name) const
|
||||
{
|
||||
BankResponse res;
|
||||
if (bank.Contains(name))
|
||||
{
|
||||
res = BankResponse(k204NoContent, std::nullopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = BankResponse(k404NotFound, "\"User not found\"");
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::AdminVerifyAccount(req_args) const
|
||||
{
|
||||
RESPOND_TRUE; //filter handles admin creds
|
||||
}
|
||||
void api::ApiProperties(req_args) const
|
||||
{
|
||||
std::string info = "{\"version\":" + std::to_string(API_VERSION) + ",\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"return_on_del\":" + std::to_string((bool)RETURN_ON_DEL);
|
||||
if constexpr (RETURN_ON_DEL)
|
||||
{
|
||||
info += ",\"" + std::string(return_account) + "\"}";
|
||||
}
|
||||
else
|
||||
{
|
||||
info += "}";
|
||||
}
|
||||
static thread_local auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
void api::AddUser(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto pass = doc.find_field("pass").get_string();
|
||||
if (name.error() || pass.error())
|
||||
{
|
||||
res = BankResponse(k400BadRequest, "\"Missing JSON arg(s)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
res = bank.AddUser(name_val.str, 0, pass_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::AdminAddUser(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
auto amount = doc.find_field("amount").get_uint64();
|
||||
auto pass = doc.find_field("pass").get_string();
|
||||
if (name.error() || amount.error() || pass.error())
|
||||
{
|
||||
res = BankResponse(k400BadRequest, "\"Missing JSON arg(s)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
res = bank.AddUser(name_val.str, amount.value(), pass_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::DelSelf(req_args) const
|
||||
{
|
||||
bank.DelSelf(NAME_PARAM);
|
||||
RESPOND_TRUE;
|
||||
}
|
||||
void api::AdminDelUser(req_args) const
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc.find_field("name").get_string();
|
||||
if (name.error())
|
||||
{
|
||||
res = BankResponse(k400BadRequest, "\"Missing JSON arg(s)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = bank.DelUser(name_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
#endif
|
||||
115
src/bank_f.cpp
115
src/bank_f.cpp
File diff suppressed because one or more lines are too long
26
src/bank_resp.cpp
Normal file
26
src/bank_resp.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "bank_resp.h"
|
||||
|
||||
template <>
|
||||
drogon::HttpResponsePtr drogon::toResponse(BankResponse &&data)
|
||||
{
|
||||
std::shared_ptr<HttpResponseImpl> res;
|
||||
if (data.second)
|
||||
{
|
||||
res = std::make_shared<HttpResponseImpl>(data.first, CT_APPLICATION_JSON);
|
||||
res->setBody(std::move(*data.second));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = std::make_shared<HttpResponseImpl>();
|
||||
res->setStatusCode(data.first);
|
||||
}
|
||||
const auto &advices = HttpAppFrameworkImpl::instance().getResponseCreationAdvices();
|
||||
if (!advices.empty())
|
||||
{
|
||||
for (auto &advice : advices)
|
||||
{
|
||||
advice(res);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
28
src/change_flag.cpp
Normal file
28
src/change_flag.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include "change_flag.h"
|
||||
|
||||
template <bool init>
|
||||
ChangeFlag<init>::ChangeFlag() noexcept {}
|
||||
template <bool init>
|
||||
ChangeFlag<init>::ChangeFlag(ChangeFlag &&f) noexcept
|
||||
{
|
||||
change_flag.store(f.GetChangeState(), std::memory_order_release);
|
||||
}
|
||||
|
||||
template <bool init>
|
||||
void ChangeFlag<init>::SetChangesOn() noexcept
|
||||
{
|
||||
return change_flag.store(1, std::memory_order_release);
|
||||
}
|
||||
template <bool init>
|
||||
void ChangeFlag<init>::SetChangesOff() noexcept
|
||||
{
|
||||
return change_flag.store(0, std::memory_order_release);
|
||||
}
|
||||
template <bool init>
|
||||
bool ChangeFlag<init>::GetChangeState() const noexcept
|
||||
{
|
||||
return change_flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
template class ChangeFlag<true>;
|
||||
template class ChangeFlag<false>;
|
||||
41
src/json_filter.cpp
Normal file
41
src/json_filter.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include "json_filter.h"
|
||||
|
||||
template <bool check_content_type>
|
||||
JsonFilter<check_content_type>::JsonFilter() {}
|
||||
|
||||
__attribute__((always_inline)) inline bool Contains(std::string_view str, const std::string &val)
|
||||
{
|
||||
return str.find(val) != std::string::npos;
|
||||
}
|
||||
|
||||
template <bool check_content_type>
|
||||
void JsonFilter<check_content_type>::doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb)
|
||||
{
|
||||
std::string_view accept_header = req->getHeader("Accept");
|
||||
if constexpr (check_content_type)
|
||||
{
|
||||
std::string_view content_type = req->getHeader("content-type");
|
||||
if (content_type == "application/json" && (Contains(accept_header, "*/*") || Contains(accept_header, "application/json")))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
const auto &resp = HttpResponse::newCustomHttpResponse(BankResponse(k406NotAcceptable, "\"Client must Accept and have content-type of JSON\""));
|
||||
fcb(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Contains(accept_header, "*/*") || Contains(accept_header, "application/json")))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
const auto &resp = HttpResponse::newCustomHttpResponse(BankResponse(k406NotAcceptable, "\"Client must Accept JSON\""));
|
||||
fcb(resp);
|
||||
}
|
||||
}
|
||||
|
||||
template class JsonFilter<true>;
|
||||
template class JsonFilter<false>;
|
||||
55
src/log.cpp
55
src/log.cpp
|
|
@ -1,22 +1,45 @@
|
|||
#include "log.h"
|
||||
|
||||
void Log::AddTrans(Transaction &&t)
|
||||
void Log::AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept
|
||||
{
|
||||
if (data.size() == max_log_size) // If we hit the max size
|
||||
log_flag.SetChangesOn();
|
||||
if (data.size() == MAX_LOG_SIZE)
|
||||
{
|
||||
for (uint32_t i = 1; i < data.size(); i++) // Make room at the back
|
||||
{
|
||||
data[i - 1] = std::move(data[i]); // Shifts everything left
|
||||
}
|
||||
data[data.size() - 1] = std::move(t); // Place new in opened spot
|
||||
return;
|
||||
data.pop_back();
|
||||
}
|
||||
else if (data.size() == data.capacity()) // If we haven't hit the max but hit capacity
|
||||
{
|
||||
data.reserve(data.capacity() + pre_log_size); // Reserve more memory
|
||||
}
|
||||
data.push_back(std::move(t)); // In either case we have space under max length, move to new spot
|
||||
data.emplace_back(from, to, amount, time);
|
||||
}
|
||||
|
||||
std::string Log::GetLogs() noexcept
|
||||
{
|
||||
if (log_flag.GetChangeState() && data.size()) //if there are changes
|
||||
{
|
||||
//re-generate snapshot
|
||||
//({\"amount\":1,\"from\":\"\",\"time\":1625943626,\"to\":\"\"}, + (2*max_name_size)+10+10) * # of logs) + 1
|
||||
size_t predicted_size = ((58 + (2 * max_name_size)) * data.size()) + 1;
|
||||
if (log_snapshot.capacity() < predicted_size)
|
||||
{
|
||||
log_snapshot.reserve(predicted_size);
|
||||
}
|
||||
log_snapshot = '[';
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
log_snapshot += "{\"to\":\"";
|
||||
log_snapshot += data[i].to;
|
||||
log_snapshot += "\",\"from\":\"";
|
||||
log_snapshot += data[i].from;
|
||||
log_snapshot += "\",\"amount\":";
|
||||
log_snapshot += std::to_string(data[i].amount);
|
||||
log_snapshot += ",\"time\":";
|
||||
log_snapshot += std::to_string(data[i].time);
|
||||
log_snapshot += "},";
|
||||
}
|
||||
log_snapshot.back() = ']';
|
||||
log_flag.SetChangesOff();
|
||||
}
|
||||
return log_snapshot;
|
||||
}
|
||||
|
||||
Json::Value Log::Serialize() const
|
||||
{
|
||||
Json::Value res;
|
||||
|
|
@ -25,7 +48,11 @@ Json::Value Log::Serialize() const
|
|||
res[i]["to"] = data[i].to;
|
||||
res[i]["from"] = data[i].from;
|
||||
res[i]["amount"] = (Json::UInt)data[i].amount;
|
||||
res[i]["time"] = (Json::UInt64)data[i].time;
|
||||
#ifdef _USE_32BIT_TIME_T
|
||||
res[i]["time"] = (Json::Int)data[i].time;
|
||||
#else
|
||||
res[i]["time"] = (Json::Int64)data[i].time;
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
12032
src/simdjson.cpp
Normal file
12032
src/simdjson.cpp
Normal file
File diff suppressed because it is too large
Load diff
45
src/str_intrusion.cpp
Normal file
45
src/str_intrusion.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "str_intrusion.h"
|
||||
|
||||
//this function is horribly jank
|
||||
template <typename Tag>
|
||||
struct result
|
||||
{
|
||||
typedef typename Tag::type type;
|
||||
static type ptr;
|
||||
};
|
||||
template <typename Tag>
|
||||
typename result<Tag>::type result<Tag>::ptr;
|
||||
|
||||
template <typename Tag, typename Tag::type p>
|
||||
struct rob : result<Tag>
|
||||
{
|
||||
struct filler
|
||||
{
|
||||
filler() { result<Tag>::ptr = p; }
|
||||
};
|
||||
static filler filler_obj;
|
||||
};
|
||||
template <typename Tag, typename Tag::type p>
|
||||
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
|
||||
struct string_length
|
||||
{
|
||||
typedef void (std::string::*type)(size_t);
|
||||
};
|
||||
template class rob<string_length, &std::string::_M_length>;
|
||||
struct string_data
|
||||
{
|
||||
typedef void (std::string::*type)(char *);
|
||||
};
|
||||
template class rob<string_data, &std::string::_M_data>;
|
||||
|
||||
StrFromSV_Wrapper::StrFromSV_Wrapper() noexcept {}
|
||||
StrFromSV_Wrapper::StrFromSV_Wrapper(std::string_view sv) noexcept
|
||||
{
|
||||
(str.*result<string_data>::ptr)((char *)sv.data());
|
||||
(str.*result<string_length>::ptr)(sv.size());
|
||||
}
|
||||
StrFromSV_Wrapper::~StrFromSV_Wrapper() noexcept
|
||||
{
|
||||
(str.*result<string_data>::ptr)(nullptr);
|
||||
(str.*result<string_length>::ptr)(0);
|
||||
}
|
||||
|
|
@ -1,15 +1,4 @@
|
|||
#include "transaction.h"
|
||||
|
||||
Transaction::Transaction() = default;
|
||||
Transaction::Transaction(std::string from_str, std::string to_str, uint32_t amount, uint64_t time) : amount(amount), time(time)
|
||||
{
|
||||
from = std::move(from_str);
|
||||
to = std::move(to_str);
|
||||
}
|
||||
Transaction::Transaction(std::string from_str, std::string to_str, uint32_t amount) : amount(amount)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
from = std::move(from_str);
|
||||
to = std::move(to_str);
|
||||
time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
Transaction::Transaction() noexcept {};
|
||||
Transaction::Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time_val) noexcept : from(from_str), to(to_str), amount(amount), time(time_val) {}
|
||||
|
|
|
|||
53
src/user.cpp
53
src/user.cpp
|
|
@ -1,19 +1,12 @@
|
|||
#include "user.h"
|
||||
|
||||
/**
|
||||
* @brief User constructor
|
||||
*
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User::User(const std::string &init_pass) : password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for admins
|
||||
*
|
||||
* @param init_bal initial balance
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User::User(uint32_t init_bal, const std::string &init_pass) : balance(init_bal), password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
User::User(uint32_t init_bal, const std::string &init_pass) noexcept : balance(init_bal), password(xxHashStringGen{}(init_pass)) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for loading
|
||||
|
|
@ -21,31 +14,39 @@ User::User(uint32_t init_bal, const std::string &init_pass) : balance(init_bal),
|
|||
* @param init_bal
|
||||
* @param init_pass
|
||||
*/
|
||||
User::User(uint32_t init_bal, uint64_t init_pass) : balance(init_bal), password(init_pass) {}
|
||||
User::User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j) : balance(init_bal), password(init_pass)
|
||||
User::User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept : balance(init_bal), password(init_pass) {}
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
User::User(const bank_dom::User &u) noexcept : balance(u.balance), password(u.password)
|
||||
{
|
||||
if (log_j.size())
|
||||
if (u.logs)
|
||||
{
|
||||
log.data.reserve(std::min(pre_log_size * ((log_j.size() / pre_log_size) + 1), max_log_size));
|
||||
for (uint32_t i = (log_j.size() - max_log_size) * (log_j.size() > max_log_size); i < log_j.size(); i++)
|
||||
for (uint32_t i = (u.logs.value().data.size() - MAX_LOG_SIZE); i < u.logs.value().data.size(); ++i)
|
||||
{
|
||||
log.data.push_back(Transaction(
|
||||
log_j[i]["from"].asCString(),
|
||||
log_j[i]["to"].asCString(),
|
||||
log_j[i]["amount"].asUInt(),
|
||||
log_j[i]["time"].asUInt64()));
|
||||
const bank_dom::Transaction &temp = u.logs.value().data[i];
|
||||
log.data.emplace_front(temp.from, temp.to, temp.amount, temp.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value User::Serialize() const
|
||||
#endif
|
||||
bank_dom::User User::Encode() const noexcept
|
||||
{
|
||||
Json::Value res;
|
||||
res["balance"] = (Json::UInt)balance;
|
||||
res["password"] = (Json::UInt64)password;
|
||||
if constexpr (max_log_size > 0)
|
||||
#if MAX_LOG_SIZE > 0
|
||||
if (this->log.data.size())
|
||||
{
|
||||
res["log"] = log.Serialize();
|
||||
bank_dom::Logs save_log;
|
||||
save_log.data.reserve(this->log.data.size());
|
||||
for (const Transaction &t : this->log.data)
|
||||
{
|
||||
save_log.data.emplace_back(t.from, t.to, t.amount, t.time);
|
||||
}
|
||||
return bank_dom::User(balance, password, save_log);
|
||||
}
|
||||
return res;
|
||||
else
|
||||
{
|
||||
return bank_dom::User(balance, password, std::nullopt);
|
||||
}
|
||||
#else
|
||||
return bank_dom::User(balance, password, std::nullopt);
|
||||
#endif
|
||||
}
|
||||
78
src/user_filter.cpp
Normal file
78
src/user_filter.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#include "user_filter.h"
|
||||
|
||||
__attribute__((always_inline)) inline bool ValidUsername(const std::string &name) noexcept
|
||||
{
|
||||
if (name.size() < min_name_size || name.size() > max_name_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool set_body_flag, bool require_admin>
|
||||
UserFilter<set_body_flag, require_admin>::UserFilter(Bank &b) : bank(b) {}
|
||||
|
||||
template <bool set_body_flag, bool require_admin>
|
||||
void UserFilter<set_body_flag, require_admin>::doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb)
|
||||
{
|
||||
std::string_view auth_header = req->getHeader("Authorization");
|
||||
if (auth_header.size() > 6 && auth_header.size() <= ((max_name_size + 256) * 4) / 3) //"Basic " + (username + ':' + password) * 4/3
|
||||
{
|
||||
if (auth_header.substr(0, 6) == "Basic ")
|
||||
{
|
||||
std::string_view input = auth_header.substr(6);
|
||||
char result_buffer[max_name_size + 256]; //(username + ':' + 255 password)
|
||||
size_t new_sz;
|
||||
base64_decode(input.data(), input.size(), result_buffer, &new_sz, 0);
|
||||
|
||||
std::string_view results_view(result_buffer, new_sz);
|
||||
std::size_t middle = results_view.find(':');
|
||||
if (middle != std::string::npos && ((new_sz - middle) <= 256))
|
||||
{
|
||||
StrFromSV_Wrapper username(results_view.substr(0, middle));
|
||||
if (ValidUsername(username.str)) //check if username is a valid attempt to avoid hashing/grabbing shared lock
|
||||
{
|
||||
if constexpr (require_admin)
|
||||
{
|
||||
if (bank.AdminVerifyAccount(username.str))
|
||||
{
|
||||
StrFromSV_Wrapper password(results_view.substr(middle + 1));
|
||||
if (bank.VerifyPassword(username.str, password.str))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper password(results_view.substr(middle + 1));
|
||||
if (bank.VerifyPassword(username.str, results_view.substr(middle + 1)))
|
||||
{
|
||||
if constexpr (set_body_flag)
|
||||
{
|
||||
req->setParameter("name", username.str);
|
||||
}
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fcb(HttpResponse::newCustomHttpResponse(BankResponse(k401Unauthorized, "\"Invalid Credentials\"")));
|
||||
}
|
||||
|
||||
template class UserFilter<true, false>; //user default
|
||||
template class UserFilter<false, false>; //user sparse
|
||||
template class UserFilter<false, true>; //admin
|
||||
10
src/xxhash_str.cpp
Normal file
10
src/xxhash_str.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "xxhash_str.h"
|
||||
|
||||
XXH64_hash_t xxHashStringGen::operator()(const std::string &str) const noexcept
|
||||
{
|
||||
return XXH3_64bits(str.data(), str.size());
|
||||
}
|
||||
XXH64_hash_t xxHashStringGen::operator()(const std::string_view &str) const noexcept
|
||||
{
|
||||
return XXH3_64bits(str.data(), str.size());
|
||||
}
|
||||
1
third_party/base64
vendored
Submodule
1
third_party/base64
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit eaebee8f666ea0451b0474e7be16006ad994004c
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"" :
|
||||
{
|
||||
"balance" : 0,
|
||||
"log" : null,
|
||||
"password" : 0
|
||||
},
|
||||
}
|
||||
Loading…
Reference in a new issue