Compare commits

...

1042 commits
v0.1.0 ... main

Author SHA1 Message Date
Expand-sys
8f85e13f11
Merge branch 'EntireTwix:main' into main 2023-01-23 01:41:58 +11:00
Expand-sys
7fcb761aa2 removed deployment script from ccash repo 2023-01-23 01:31:23 +11:00
EntireTwix
caf1d65e16 🐛 correcting last commit 2023-01-18 17:19:30 -08:00
EntireTwix
a61a590f3a cleaned up 2023-01-18 15:54:45 -08:00
EntireTwix
32f5f2a2be daemon flag error 2023-01-18 15:36:49 -08:00
EntireTwix
a98b84955c start is 0-indexed so == to data.size() is out of bounds 2023-01-12 16:51:09 -08:00
EntireTwix
c970b6a42f loosened endpoint restrictions 2023-01-12 16:33:01 -08:00
EntireTwix
f2da8cdbc2 optimizing GetLogsRange 2023-01-12 16:29:13 -08:00
EntireTwix
af551ef8b4 🐛 correcting last commit 2023-01-12 13:27:53 -08:00
EntireTwix
511aa76795 🐛 correcting last commit 2023-01-12 13:17:54 -08:00
EntireTwix
eea9c4b566 rest of log optimization 2023-01-12 12:26:42 -08:00
EntireTwix
cb5d12d4dc made GetLogsV2 newest to oldest transaction 2023-01-12 01:05:23 -08:00
EntireTwix
01aedef7a3 rest of log optimization 2023-01-12 00:55:08 -08:00
EntireTwix
6ddcf08797 📝 GetLogsRange 2023-01-12 00:33:35 -08:00
EntireTwix
4a41cb1ef4 🐛 how did this bug go unnoticed for so long 2023-01-12 00:31:03 -08:00
EntireTwix
dda98f346e GetLogsRange 2023-01-12 00:18:42 -08:00
EntireTwix
2419641cd0 🐛 fixed unsigned underflow when negative 2023-01-10 22:21:38 -08:00
EntireTwix
6dad3ed0af 📝 2023-01-10 22:13:59 -08:00
EntireTwix
88458de0f0 📝 added AdminGetLogs and reordered 2023-01-10 21:59:36 -08:00
EntireTwix
47649d6ccd AdminGetLogs 2023-01-10 21:58:05 -08:00
EntireTwix
370107e3f9 📝 ValidUsername should allow capitilization 2023-01-09 21:13:50 -08:00
EntireTwix
8fea062a3f 🐛 fixed 2023-01-09 18:37:40 -08:00
EntireTwix
779ab90b8f omega symbol 2023-01-09 17:30:25 -08:00
EntireTwix
0d346b820f 🐛 fixing last log commit 2023-01-09 17:10:41 -08:00
EntireTwix
c659c9b7bd 🐛 ValidUsername should allow capitilization 2023-01-09 17:01:14 -08:00
EntireTwix
5e996b2705 ImpactBal and SetBal add a log now 2023-01-09 16:43:54 -08:00
EntireTwix
7e1954d651 📝 2022-12-28 18:16:56 -08:00
Expand-sys
ad3bb2c13b allow ccash ports to be set by vars 2022-12-25 10:01:34 +11:00
William
b74510a113
🐛 invalid json after last commit 2022-12-24 00:55:21 -08:00
William
4aa55486c9
Merge pull request #50 from Expand-sys/patch-1
change default branch on deployment
2022-12-24 00:44:21 -08:00
Expand-sys
e413c089dc
change default branch on deployment 2022-12-24 19:19:14 +11:00
William
a195e8c5a2
Merge pull request #49 from EntireTwix/logs-optimization
Logs optimization
2022-12-23 19:33:45 -08:00
EntireTwix
396b676ee5 📝 updating GetLogsV2 docs 2022-12-23 19:32:28 -08:00
EntireTwix
dce87bbcfa Merge branch 'logs-optimization' of https://github.com/EntireTwix/CCash into logs-optimization 2022-12-23 19:07:41 -08:00
EntireTwix
705a746a3c 📝 157 bytes -> 139 2022-12-23 19:06:31 -08:00
EntireTwix
6e6d722f9f 📝 157 bytes -> 139 2022-12-23 19:05:26 -08:00
EntireTwix
70ac88e894 receiving does not have to be a json field 2022-12-23 19:03:08 -08:00
EntireTwix
6f1bd193d5 📝 2022-12-23 00:43:20 -08:00
EntireTwix
69a2f81454 📝 2022-12-20 17:20:28 -08:00
EntireTwix
113f42a399 📝 2022-12-20 16:58:19 -08:00
EntireTwix
3629b78e38 2022-12-20 15:34:57 -08:00
William
282bd5e423
Merge pull request #48 from EntireTwix/v2.5.1
V2.5.1
2022-12-20 13:35:18 -08:00
EntireTwix
b656bb7e43 📝 python lib up to date 2022-12-20 13:17:45 -08:00
EntireTwix
3b46c97d0a 📝 return_on_del is always a field now 2022-12-20 12:06:40 -08:00
EntireTwix
3e73d08227 🔥 return_on_del is always a field now 2022-12-20 11:56:50 -08:00
EntireTwix
82e3a6384c 📝 2022-12-19 20:07:49 -08:00
EntireTwix
d303016124 Merge branch 'v2.5.1' of https://github.com/EntireTwix/CCash into v2.5.1 2022-12-19 19:55:59 -08:00
EntireTwix
66b21332b3 🐛 fixed properties() 2022-12-19 19:55:52 -08:00
William
34039f9fcf
Merge pull request #47 from Expand-sys/v2.5.1
added pending changes to deployment script
2022-12-19 19:10:39 -08:00
Expand-sys
ce65a4387c made ccash use crontab to start it on boot 2022-12-20 14:01:55 +11:00
EntireTwix
95c2d47216 receiving output as "true" instead of "1" 2022-12-19 18:41:15 -08:00
Expand-sys
8696c5d870 added pending changes to deployment script 2022-12-20 13:35:34 +11:00
EntireTwix
dbe755da2b 📝 2022-12-19 17:47:41 -08:00
EntireTwix
24665641b4 📝 versioning changes 2022-12-19 17:44:49 -08:00
EntireTwix
026d2b8493 📝 versioning changes 2022-12-19 17:43:13 -08:00
EntireTwix
99f47dc6ed 📝 versioning changes 2022-12-19 17:31:38 -08:00
EntireTwix
d8e88ec375 📝 versioning documented 2022-12-19 16:26:00 -08:00
EntireTwix
8ff1fddf7a 📝 2022-12-19 16:07:34 -08:00
EntireTwix
07b9e20e31 expand's commit 2022-12-19 15:48:08 -08:00
EntireTwix
83455a0510 changed to per-method versioning 2022-12-19 15:45:05 -08:00
EntireTwix
cc103c7298 📝 2022-12-18 23:23:53 -08:00
EntireTwix
10c3c6a536 ✖️ -> 2022-12-18 22:27:29 -08:00
EntireTwix
21fd1c94e4 📝 connect services versioning documented 2022-12-18 22:26:44 -08:00
EntireTwix
b69092d732 📝 command line arguments example 2022-12-18 20:24:33 -08:00
EntireTwix
472a9222fc daemon flag 2022-12-18 20:16:52 -08:00
EntireTwix
878a71f310 🐛 fixing last commit 2022-12-18 19:11:26 -08:00
EntireTwix
411d1996c7 🐛 used CMake variables incorrectly 2022-12-18 19:09:55 -08:00
EntireTwix
722f8d0f48 🐛 correcting last commit 2022-12-18 18:35:26 -08:00
EntireTwix
aefdb4ce9b more accurate thread readout 2022-12-18 18:34:35 -08:00
EntireTwix
76388c6423 📝 mistaken ✖️ 2022-12-18 17:56:20 -08:00
EntireTwix
ff0dfc8a93 📝 2022-12-18 17:28:02 -08:00
EntireTwix
5e253e42d9 🐛 fixing last commit 2022-12-18 17:22:12 -08:00
EntireTwix
d63be0ec73 🐛 logs being disabled wasnt building 2022-12-18 17:18:47 -08:00
EntireTwix
4ca1bbe6eb 📝 2022-12-18 16:51:23 -08:00
EntireTwix
54acbf8cc6 🐛 "doc["time"].get(pass)" -> "doc["pass"].get(pass)" 2022-12-18 15:48:28 -08:00
EntireTwix
2c62c89b47 💡 clarifying comment 2022-12-18 13:22:46 -08:00
EntireTwix
37b110d36f 🐛 receiving field should not be in quotes 2022-12-17 12:25:47 -08:00
William
8e44a3d446
Update FAQ.md 2022-12-17 09:18:50 -08:00
William
e20ac4cebc
Merge pull request #45 from Expand-sys/main
updated the variables fle for ansible
2022-12-13 02:43:37 -08:00
Expand-sys
19b6acc48f
Merge branch 'EntireTwix:main' into main 2022-12-11 11:16:34 +11:00
Expand-sys
ed0d5c8231 update ansible to allow for api version changes 2022-12-11 11:14:55 +11:00
EntireTwix
6d9c6d6c1c 📝 corrected 2022-12-09 04:06:04 -08:00
EntireTwix
04fe7376ec 📝 2022-12-09 04:04:30 -08:00
EntireTwix
292b73001e 📝 simplified 2022-12-09 04:02:33 -08:00
EntireTwix
c8791ec7ce 📝 clarified path 2022-12-09 04:02:14 -08:00
EntireTwix
a308f830c0 📝 2022-12-04 00:40:04 -08:00
EntireTwix
a49a1730f7 🐛 fixed MIN_API_SUPPORT commit 2022-12-04 00:17:11 -08:00
EntireTwix
0b7de8b905 📝 doggo ->ArcNyxx 2022-12-04 00:07:04 -08:00
EntireTwix
b674a6dded 🎨 help and properties are version independent 2022-12-04 00:04:31 -08:00
EntireTwix
49b5b7d35d 📝 help and properties are version independent 2022-12-04 00:04:17 -08:00
EntireTwix
f9aa33afac updated ApiProperties 2022-12-03 23:56:07 -08:00
EntireTwix
da65fb678a 📝 MIN_API_SUPPORT 2022-12-03 23:55:20 -08:00
EntireTwix
7850c721e5 Merge branch 'v2' of https://github.com/EntireTwix/CCash into v2 2022-12-03 23:45:37 -08:00
EntireTwix
09422995e8 MIN_API_SUPPORT 2022-12-03 23:45:19 -08:00
William
d5f5b41e20
Merge pull request #44 from Expand-sys/patch-7
Update deploy.md
2022-12-03 18:09:32 -08:00
Expand-sys
7d4a564513
Update deploy.md
added ansible docs and changed docker link to use auto built docker image
2022-12-04 13:05:18 +11:00
EntireTwix
a68e86b216 📝 2022-11-30 20:37:31 -08:00
EntireTwix
a9e3ca1665 📝 backwards compatibility noted 2022-11-30 20:31:08 -08:00
EntireTwix
f6d8673045 🐛 GetLogsV2 also needs a log_flag 2022-11-30 20:14:25 -08:00
EntireTwix
206698697b 🐛 forgot usernames must be <3 characters 2022-11-30 20:14:11 -08:00
EntireTwix
f1b03ecb41 🐛 GetLogsV2 also needs a log_flag 2022-11-30 19:17:19 -08:00
EntireTwix
94c2cb1f65 🐛 used old log_snapshot 2022-11-30 19:14:22 -08:00
EntireTwix
7c31b4d680 GetLogsV2 and NumOfUsers output 2022-11-30 19:08:19 -08:00
EntireTwix
b874af86af 🐛 messed up RETURN_ON_DEL_NAME cmake var 2022-11-30 17:03:34 -08:00
EntireTwix
73a80de08e 🐛 broken cmake 2022-11-28 18:37:38 -08:00
EntireTwix
35c50ac0f4 📝 2022-11-28 18:20:21 -08:00
EntireTwix
4892ec2655 📝 2022-11-28 18:13:00 -08:00
EntireTwix
d46fe68559 📝 2022-11-28 18:12:00 -08:00
EntireTwix
52677f0576 API_VERSION settable from cmake 2022-11-28 18:02:14 -08:00
EntireTwix
d2f0989a15 📝 noting that existing apis dont support v2 2022-11-28 17:45:31 -08:00
EntireTwix
ecb602d6f2 📝 2022-11-28 17:43:43 -08:00
EntireTwix
a068502643 📝 updated endpoint logs for new GetLogV2 2022-11-28 17:41:38 -08:00
EntireTwix
49816dc18c updated at launch stats 2022-11-28 17:35:36 -08:00
EntireTwix
e100444042 🔥 temporary comment 2022-11-28 17:35:22 -08:00
EntireTwix
4fd3eb2bd8 📝 updated stats on log size in memory/disk 2022-11-28 17:34:52 -08:00
EntireTwix
cf4ba5ccfa api_version related changes 2022-11-28 17:14:41 -08:00
William
244ca2561c
Merge pull request #43 from EntireTwix/transaction_optimization
Transaction Optimization
2022-11-28 17:10:24 -08:00
EntireTwix
b584f5b4d5 improved Transaction structure 2022-11-28 17:06:13 -08:00
EntireTwix
ab27971d8e 💡 comment clarification 2022-11-28 16:41:27 -08:00
EntireTwix
7387156d15 🔥 unessasary macro 2022-11-28 16:41:08 -08:00
EntireTwix
47d544070b 💡 comment error and API_VERSION incremented 2022-11-28 16:40:07 -08:00
EntireTwix
1f983322a1 updated fbe for new transaction struct 2022-11-28 16:39:32 -08:00
EntireTwix
5a754a567c config file isnt subject to commits 2022-11-24 11:22:01 -08:00
EntireTwix
83f149677d 📝 2022-11-24 11:21:40 -08:00
William
61134740f0
📝 fixed rust api link 2022-11-24 09:45:00 -08:00
EntireTwix
78b62092b3 🐛 correction to last commit 2022-11-21 22:53:28 -08:00
EntireTwix
1b2c763f0b requests that accept 2^32 reject arguments larger than 2^32 2022-11-21 22:20:59 -08:00
EntireTwix
a8b7defb36 📝 2022-11-21 22:10:55 -08:00
EntireTwix
1498d3d028 🐛 doc["time"].get(amount) 2022-11-21 22:10:50 -08:00
William
dffd20511d
📝 mentioned Docker and Ansible support 2022-11-20 21:29:30 -08:00
William
6c8ebfa57c
Merge pull request #42 from Expand-sys/main
fix some things in docker and add ansible playbook deployment
2022-11-20 20:36:49 -08:00
Expand-sys
decfd83931 docker file and ansible playbook addition 2022-11-21 15:31:54 +11:00
Expand-sys
89448a4b12
Merge branch 'EntireTwix:main' into main 2022-11-21 15:28:09 +11:00
EntireTwix
2fa6a7a743 🔥 file generation 2022-11-20 20:10:30 -08:00
EntireTwix
d56599f49a 🐛 return on del arg 2022-11-20 20:10:12 -08:00
William
df21ce4131
Merge pull request #41 from Expand-sys/patch-6
Update CMakeLists.txt
2022-11-20 19:36:25 -08:00
Expand-sys
dcbb65ab6f
Update CMakeLists.txt
yeet
2022-11-21 14:02:51 +11:00
Expand-sys
5999a00d68
Update CMakeLists.txt
smh my leg my armpit and my dog, twix doesnt know how to escape characters.

fixed escaping quotations.
2022-11-21 13:55:42 +11:00
EntireTwix
e04cd1af04 🐛 2022-11-20 18:20:32 -08:00
EntireTwix
90add46113 user.json -> user.data 2022-11-20 17:38:37 -08:00
EntireTwix
c0b02fa7aa 🚚 moved user data to config folder 2022-11-20 17:37:56 -08:00
EntireTwix
9761aa93b5 🐛 line was not superfulous 2022-11-20 17:26:14 -08:00
EntireTwix
e536bb94fb changed default config.json location 2022-11-20 17:16:17 -08:00
William
279481532e
🐛 config and user location should be in quotes 2022-11-20 13:04:22 -08:00
EntireTwix
0fc044fdda 📝 2022-11-19 22:01:05 -08:00
EntireTwix
5e71954391 🐛 massive seg fault bug 2022-11-19 21:49:59 -08:00
EntireTwix
c9f7e103ce 📝 grammar 2022-11-19 21:49:47 -08:00
EntireTwix
6cf167b42d 📝 reprhased 2022-11-19 21:49:30 -08:00
EntireTwix
3f08055dd0 🔥 superfluous line 2022-11-19 21:49:15 -08:00
EntireTwix
1776eaea2f desired connected services 2022-11-19 15:46:31 -08:00
EntireTwix
50c88aa32f corrected URL and name of doggo 2022-11-19 15:26:59 -08:00
EntireTwix
46c97fd813 clarifying error message 2022-02-16 16:26:56 -08:00
William Katz
e8576b76f8
Update FAQ.md 2021-12-09 23:36:42 -08:00
William Katz
d71d74678e
Merge pull request #36 from EntireTwix/AddUserToggle
AddUser toggle
2021-12-02 12:39:57 -08:00
EntireTwix
32e91a188a AddUser is togglable now 2021-12-02 12:09:52 -08:00
EntireTwix
5026285d1b 📝 explanation for ADD_USER_OPEN 2021-12-02 12:09:08 -08:00
EntireTwix
38dfed90cb 📝 updating docs to include 404 for AddUser 2021-12-02 12:08:48 -08:00
EntireTwix
7cba136a78 ADD_USER_OPEN variable 2021-12-02 12:08:04 -08:00
EntireTwix
3d3ee3cc0a ADD_USER_OPEN macro 2021-12-02 12:07:45 -08:00
William Katz
44af19bfd5
📝 simplified 2021-11-28 12:31:35 -08:00
William Katz
de3ec4a5c9
📝 2021-11-28 11:28:18 -08:00
William Katz
93c0b39e11
📝 grammar 2021-11-28 11:24:25 -08:00
William Katz
f1c22cb136
📝 disk space question 2021-11-28 11:21:34 -08:00
William Katz
8975564876
📝 more questions added 2021-11-28 11:17:01 -08:00
EntireTwix
8c911675c7 SIGTERM and other signal handling 2021-11-22 17:04:45 -08:00
EntireTwix
1d76bc54bd 🔥 removed legacy Json() and JsonCpp 2021-11-22 02:00:50 -08:00
William Katz
ec0d5900c1
📝 updated doggo's cmd URL 2021-11-09 22:32:40 -08:00
William Katz
b4a72649fd
📝 doggo's cmd is done 2021-11-09 22:31:55 -08:00
William Katz
9e5378eb74
🐛📝 DelSelf cant return 404 2021-11-08 13:56:55 -08:00
William Katz
d5aeef7868
📝 added logo 2021-11-02 17:50:27 -07:00
William Katz
25e765d6b3
📝 2021-10-29 03:05:33 -07:00
William Katz
ca303d8599
📝 2021-10-29 02:52:44 -07:00
William Katz
520e008f25
📝 2021-10-29 02:52:20 -07:00
William Katz
ac559d1d9a
Update APIs.md 2021-10-28 19:06:04 -07:00
William Katz
7489b6d93b
Update APIs.md 2021-10-28 19:03:28 -07:00
William Katz
06d62097c4
📝 example 2021-10-28 19:03:03 -07:00
William Katz
d88538d0db
📝 2021-10-28 18:29:55 -07:00
William Katz
01efbb7dd4
🎨 stylistic 2021-10-15 14:34:51 -07:00
William Katz
474b8b0d47
🐛 fixed error message 2021-10-15 14:27:39 -07:00
William Katz
4d54da90b8
📝 fixed build docs 2021-10-15 14:18:21 -07:00
William Katz
308f75ec37
📝 forgot build-essential 2021-10-15 14:11:10 -07:00
William Katz
a4a9473b07
other distros categoruy 2021-09-23 23:41:57 -07:00
EntireTwix
c083d78ac1 improved errors 2021-09-23 23:16:46 -07:00
William Katz
348c3b6e12
warning in exception throw 2021-09-23 22:59:52 -07:00
William Katz
b8ba5d49b5
📝 2021-09-23 22:51:44 -07:00
William Katz
0f918f6b24
Delete deploy.yaml 2021-09-22 17:11:40 -07:00
William Katz
7e617f9c34
📝 updated 2021-09-22 15:35:22 -07:00
William Katz
fc7b03fa1a
📝 typo 2021-09-22 15:06:54 -07:00
William Katz
f551df92cb
📝 "How do I setup a CCash instance" 2021-09-22 14:43:21 -07:00
EntireTwix
5114e19737 🐛 fixed last commit 2021-08-11 17:10:05 -07:00
EntireTwix
ae7f3e7cfa more portable way of force inlining 2021-08-10 19:57:44 -07:00
William Katz
2823a6fe3f
🐛 when max log grew since last save, the load would underflow 2021-08-01 00:44:37 -07:00
William Katz
2089b5ed97
made return on del name assignable easier 2021-07-31 23:50:45 -07:00
William Katz
491e4bcc85
updated redirect url 2021-07-31 23:39:01 -07:00
William Katz
7d26eb9341
made more portable 2021-07-31 23:05:52 -07:00
William Katz
4914490b42
🐛 made inline 2021-07-31 22:49:33 -07:00
William Katz
e399a5bc16
constexpr will fail but inline, is more portable 2021-07-31 22:44:40 -07:00
EntireTwix
09408ae800 🔥 "#include <chrono>" 2021-07-31 22:11:10 -07:00
EntireTwix
5f74e0ce12 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-31 22:07:36 -07:00
EntireTwix
88f67ae992 🔥 "#include <iostream>" 2021-07-31 22:07:02 -07:00
EntireTwix
b0ce1acb56 🔥 "using namespace std::chrono;" 2021-07-31 22:06:50 -07:00
William Katz
0fb70a9ba9
Merge pull request #35 from Expand-sys/patch-5
Update deploy.md
2021-07-31 19:14:23 -07:00
Expand-sys
942e6b702a
Update deploy.md 2021-08-01 12:11:40 +10:00
EntireTwix
ab41a7ed46 📝🔥 removed unessasary Docker section 2021-07-31 18:33:05 -07:00
EntireTwix
f951bc6845 📝 forgot PruneUsers and ApiProperties 2021-07-31 17:21:14 -07:00
EntireTwix
f8dfe184a4 📝 updated path to ATM 2021-07-31 16:40:53 -07:00
EntireTwix
7e06ae704c 📝 ATM is not yet working 2021-07-31 16:35:57 -07:00
EntireTwix
0db2fa7130 📝 2021-07-31 16:30:57 -07:00
EntireTwix
c6b58d60cd 📝 React fixed services 2021-07-31 16:06:20 -07:00
EntireTwix
b7f2ad3b5f Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-31 15:57:05 -07:00
William Katz
d4638278d4
Merge pull request #34 from Expand-sys/patch-4
Updated dockerfile to generate save file at build
2021-07-31 15:55:05 -07:00
Expand-sys
c323e49451
Updated dockerfile to generate save file at build 2021-08-01 08:51:58 +10:00
William Katz
d543ab0a89
Merge pull request #33 from Expand-sys/patch-3
Update deploy.md
2021-07-31 15:47:16 -07:00
EntireTwix
b821607d60 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-31 13:56:00 -07:00
William Katz
ec2abe8750
📝 Rust API done! 2021-07-31 13:48:42 -07:00
Expand-sys
956165ea6d
Update deploy.md 2021-07-31 20:05:21 +10:00
William Katz
f6cc2b2f52
📚 link to docker docs 2021-07-31 03:02:05 -07:00
EntireTwix
8ad656624d 🐛 real max log size is 59 not 60 2021-07-29 21:30:36 -07:00
EntireTwix
b3cc2b2cb5 🐛 forgot to resize to 0 of string cache 2021-07-29 20:57:03 -07:00
EntireTwix
96d3c1de08 🐛 real max log size is 59 not 60 2021-07-29 20:53:53 -07:00
EntireTwix
4cfc27e01e 🐛 real max log size is 59 not 60 2021-07-29 20:48:53 -07:00
EntireTwix
be90601801 🐛 real max log size is 60 not 58 2021-07-29 20:46:34 -07:00
EntireTwix
9a67d223dc 🔥 removed thread_local for cached responses 2021-07-28 17:41:44 -07:00
EntireTwix
24053efeb8 📚 2021-07-28 17:33:32 -07:00
EntireTwix
220c998312 made JSON member parsing order independent 2021-07-28 17:21:58 -07:00
EntireTwix
61345092f5 📚 wrong word 2021-07-28 12:41:17 -07:00
EntireTwix
b409d42c96 📚🔥 removed React's api 2021-07-28 12:30:25 -07:00
EntireTwix
9f1c1b1edc 📚🔥 removed React's api 2021-07-28 12:27:58 -07:00
EntireTwix
447a9becc8 📚 2021-07-28 12:15:41 -07:00
EntireTwix
1890ba1ca6 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-28 12:14:38 -07:00
EntireTwix
2156afa774 📚 2021-07-28 12:14:16 -07:00
William Katz
01bc8dfc26 Update issue templates 2021-07-28 01:14:23 -07:00
William Katz
d485e3a21d Update issue templates 2021-07-28 01:09:32 -07:00
EntireTwix
e780a1546c changed PruneUsers benchmark from Op_a to Op 2021-07-28 00:46:19 -07:00
EntireTwix
a05ad5fc3d 📚 Jolly -> Sam 2021-07-28 00:43:23 -07:00
EntireTwix
6e7a263907 added 10K users to stress benchmark 2021-07-27 17:18:07 -07:00
EntireTwix
7d0d78c698 📚🚧 2021-07-27 16:35:04 -07:00
EntireTwix
385d8a0027 📚 fixed base memory usage 2021-07-27 16:32:04 -07:00
William Katz
edd65e1a2b
📚 more info 2021-07-27 15:57:15 -07:00
William Katz
28d1fca04b
📚 renamed APIs 2021-07-27 14:31:50 -07:00
EntireTwix
e717a0ad2c 🐛 JSON input should not be static thread_local 2021-07-25 11:03:03 -07:00
EntireTwix
7ce9a71118 small tweaksg 2021-07-24 17:42:41 -07:00
EntireTwix
0f50e00b6c 🐛 fixed for CONSERVATIVE_DISK_SAVE false possibility 2021-07-24 17:29:25 -07:00
EntireTwix
37d885d81d 🚚🔥 removed save_flag as bool possibility & moved static declarations from bank_api.cpp 2021-07-24 17:26:15 -07:00
EntireTwix
edee4f2e0d 🔥 removed save_flag as bool possibility 2021-07-24 17:25:43 -07:00
EntireTwix
0f28a0cc19 🚚🐛 moved static declarations & fixed RESPONSE_PARSE 2021-07-24 17:25:20 -07:00
EntireTwix
1120b7b4d0 📚:construction 2021-07-24 14:45:45 -07:00
EntireTwix
72ed06aff6 📚:construction 2021-07-24 13:26:47 -07:00
EntireTwix
7760a8e8ca updated for recent commits 2021-07-23 22:58:18 -07:00
EntireTwix
2d84be675a 🐎🔥 made all filters AutoCreated rather then instance bound 2021-07-23 22:48:09 -07:00
EntireTwix
0cae801ba3 🐎🔥 made BankAPI static 2021-07-23 22:43:47 -07:00
EntireTwix
4086a1d324 🐎🔥 made Bank static 2021-07-23 22:38:51 -07:00
William Katz
8abee602b7
📚🚧 2021-07-23 15:41:51 -07:00
William Katz
545958c2de
update PruneUsers() description 2021-07-23 15:39:51 -07:00
EntireTwix
dbaa6c6beb 🐎 optimized PruneUsers() for if logs are disabled 2021-07-23 15:36:24 -07:00
EntireTwix
2b7330f48a 🐎 balance can be accumulated rather then each account adding to return_on_del individually 2021-07-23 15:30:44 -07:00
EntireTwix
86ab683704 🐎 bal must be non-zero to impact return account 2021-07-23 15:24:18 -07:00
EntireTwix
ce9b431cfe 📚🚧 2021-07-23 15:14:11 -07:00
William Katz
7a0a5d4036
🐛 prune users should return on del if enabled 2021-07-23 15:12:12 -07:00
EntireTwix
f48ad92f25 📚🚧 2021-07-23 14:59:23 -07:00
EntireTwix
948aa93cc2 🔥 removed duplicate config.json 2021-07-23 14:33:07 -07:00
William Katz
5e7243c55a
🔥 no longer needed 2021-07-22 19:59:48 -07:00
William Katz
4b43ecf11c
📚🚧 2021-07-22 19:51:45 -07:00
William Katz
2161482fdd
Update idea.md 2021-07-22 19:45:09 -07:00
William Katz
2f6579ea88
changed to GPL2 2021-07-22 01:30:23 -07:00
William Katz
bd63f39d02
🔥 legacy docs 2021-07-22 01:23:11 -07:00
William Katz
293414953d
🔥 legacy docs 2021-07-22 01:22:16 -07:00
William Katz
0beef17226
🔥 legacy docs 2021-07-22 01:22:01 -07:00
William Katz
051a26c7cd
Python API completed 2021-07-22 00:06:49 -07:00
EntireTwix
212bfc7ce9 📚🚧 2021-07-21 23:32:02 -07:00
William Katz
613123ba64
🎨🐎 simplification of log of last commit 2021-07-21 23:08:32 -07:00
William Katz
67183d88eb
🐛 when logs were empty .back() would seg fault 2021-07-21 23:00:24 -07:00
EntireTwix
88ec95968c Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-21 12:31:26 -07:00
EntireTwix
d544a10bf1 🐛 static thread_local document breaks parsing overtime 2021-07-21 12:31:02 -07:00
William Katz
a122a8e8a9
Updated path 2021-07-21 00:44:04 -07:00
EntireTwix
6da7cd087c 🐛 messed up path 2021-07-20 16:43:09 -07:00
EntireTwix
cb88bc8495 🐛 fixed lock order 2021-07-20 13:55:22 -07:00
EntireTwix
c787f4476f 📚🚧 2021-07-20 00:31:05 -07:00
EntireTwix
5feb20754a 🐛 fixed seg fault bug (I think) 2021-07-20 00:28:06 -07:00
EntireTwix
a5da4c9a04 🎨 simplified with macro 2021-07-20 00:14:21 -07:00
EntireTwix
e610615e5f 🐛 erasing users should set save flag 2021-07-20 00:09:16 -07:00
EntireTwix
b66f2dc562 🐛 patched for MAX_LOG_SIZE > 0 usecase 2021-07-19 23:36:19 -07:00
EntireTwix
dc9b2e70c2 🔥 removed legacy code 2021-07-19 23:35:04 -07:00
EntireTwix
3bb7640cd6 🐛 patched for MAX_LOG_SIZE == 1 usecase 2021-07-19 23:33:03 -07:00
EntireTwix
a37825fd51 📚🚧 2021-07-19 23:11:24 -07:00
EntireTwix
d296e1da17 📚 links 2021-07-19 22:54:12 -07:00
William Katz
196b6b43f4
added docs folder 2021-07-19 22:47:07 -07:00
EntireTwix
5a488814c4 📚🚧 2021-07-19 22:46:21 -07:00
EntireTwix
1406c291d7 🚚 moved API properties into v1 endpoints 2021-07-19 22:36:43 -07:00
EntireTwix
1df473f49a 🐛 fixed last commit 2021-07-19 22:35:51 -07:00
EntireTwix
9212edb9a3 updated ApiProperties 2021-07-19 22:35:33 -07:00
EntireTwix
0c15121ef0 🚚 moved API properties into v1 endpoints 2021-07-19 22:35:08 -07:00
EntireTwix
5704d4668a 📚 ApiProperties endpoint documented 2021-07-19 22:34:27 -07:00
EntireTwix
8a7a4680e0 🔒 static_assert for safety 2021-07-19 22:34:00 -07:00
EntireTwix
72864e6c18 PruneUsers() endpoint 2021-07-19 22:21:18 -07:00
EntireTwix
c99e542111 🎨 stylistic 2021-07-19 22:18:10 -07:00
EntireTwix
14b1bff364 🚚 renamed save_lock & made PruneUsers() 2021-07-19 22:08:46 -07:00
EntireTwix
34099acd02 🎨 stylistic change to list init for pairs 2021-07-19 22:08:09 -07:00
EntireTwix
91609f1840 🔥 removed AdminVerifyAccount() 2021-07-19 22:07:21 -07:00
EntireTwix
8190f18408 💡 comments & PruneUsers() 2021-07-19 22:07:00 -07:00
William Katz
d63dd6a540
Merge pull request #31 from Expand-sys/patch-2
Update Dockerfile
2021-07-19 17:44:56 -07:00
Expand-sys
a1acb6ff0e
Update Dockerfile 2021-07-20 10:43:32 +10:00
William Katz
50a0aeb0c3
Merge pull request #30 from EntireTwix/Refractor
Complete Refactor
2021-07-19 17:39:36 -07:00
William Katz
feb60c13a1
Merge branch 'main' into Refractor 2021-07-19 17:39:26 -07:00
EntireTwix
5596e5395a 📚🚧 2021-07-19 17:17:21 -07:00
EntireTwix
ba62ff5ab9 📚🚧 2021-07-19 17:15:53 -07:00
EntireTwix
b74db4cf7d 📚🚧 2021-07-17 21:33:49 -07:00
EntireTwix
e4f022cf46 📚🚧 2021-07-17 21:28:24 -07:00
EntireTwix
8c660595c9 made Contains respond 204/404 instead of bool 2021-07-17 20:46:14 -07:00
EntireTwix
62efbd396d 📚🚧 2021-07-15 22:09:43 -07:00
EntireTwix
7db986dcf6 📚🚧 2021-07-15 21:52:00 -07:00
EntireTwix
643f3925b9 📚🚧 2021-07-15 21:42:57 -07:00
William Katz
9da47134af
Update implementation.md 2021-07-15 21:20:51 -07:00
EntireTwix
2daed041f9 📚🚧 2021-07-15 21:18:50 -07:00
EntireTwix
598f73ff22 📚🚧 2021-07-15 21:17:19 -07:00
William Katz
ef69b29761
Update implementation.md 2021-07-15 21:16:10 -07:00
EntireTwix
5eaf38baab 📚🚧 2021-07-15 21:14:56 -07:00
EntireTwix
a93e6a3796 📚🚧 2021-07-15 21:12:14 -07:00
EntireTwix
97fde5cdcc 📚🚧 2021-07-15 21:11:17 -07:00
EntireTwix
9e359e40f5 📚🚧 2021-07-15 21:00:49 -07:00
EntireTwix
c1c456aca4 📚🚧 2021-07-15 20:39:34 -07:00
EntireTwix
ededc24be4 📚🚧 2021-07-15 20:31:10 -07:00
EntireTwix
e3c7336f03 📚🚧 2021-07-15 20:29:21 -07:00
EntireTwix
024ffe8bb9 📚🚧 2021-07-15 20:23:30 -07:00
EntireTwix
dc399184cf 📚🚧 2021-07-15 20:18:38 -07:00
EntireTwix
efca0b8034 📚🚧 2021-07-15 20:17:13 -07:00
EntireTwix
47e84ced7a 📚🚧 2021-07-15 20:09:04 -07:00
EntireTwix
b7d75bfe74 📚🚧 2021-07-15 20:05:11 -07:00
EntireTwix
54c8f95b6c 📚🚧 2021-07-15 20:02:54 -07:00
EntireTwix
018e8dac83 📚🚧 2021-07-15 20:00:59 -07:00
EntireTwix
c11bf24d90 📚🚧 2021-07-15 19:34:54 -07:00
EntireTwix
335fd4983c 📚🚧 2021-07-15 19:33:36 -07:00
EntireTwix
3650bff3f0 📚🚧 2021-07-15 19:06:01 -07:00
EntireTwix
03767fb61d 📚🚧 2021-07-15 19:02:14 -07:00
EntireTwix
c69c717ed1 📚🚧 2021-07-15 18:59:04 -07:00
EntireTwix
b64c18fc22 📚🚧 2021-07-15 18:46:33 -07:00
EntireTwix
54e59e47b2 📚🚧 2021-07-15 18:45:33 -07:00
EntireTwix
86fa298e04 📚🚧 2021-07-15 18:44:25 -07:00
EntireTwix
c2da258143 📚🚧 2021-07-15 18:37:23 -07:00
EntireTwix
9554fd0cc6 📚🚧 2021-07-15 18:34:24 -07:00
EntireTwix
22d1c27af2 📚🚧 2021-07-15 18:33:29 -07:00
EntireTwix
cc9196dce5 📚🚧 2021-07-15 18:31:41 -07:00
EntireTwix
347c9490fd Help() should respond with 301 2021-07-15 18:30:55 -07:00
EntireTwix
74b45a1775 🚚 renmaed DelUser to DelSelf 2021-07-15 18:22:41 -07:00
EntireTwix
14287cf7b4 📚🚧 2021-07-15 18:12:14 -07:00
EntireTwix
df601fad65 📚🚧 2021-07-15 18:09:07 -07:00
EntireTwix
83d2ad4262 💡 fixed comments 2021-07-15 17:24:45 -07:00
EntireTwix
a4670cb5f6 🐎🔥 removed intermediate vector 2021-07-15 17:19:18 -07:00
EntireTwix
162b421c8b 🐛 admin changepass should be able to respond with 404 2021-07-15 15:39:16 -07:00
EntireTwix
822a0d2647 🚧📚 2021-07-15 15:29:49 -07:00
EntireTwix
89f268889c 🔥 remove legacy clear() 2021-07-15 14:49:17 -07:00
EntireTwix
4ca3ac2528 🚧📚 2021-07-15 14:27:09 -07:00
EntireTwix
74f97ecac9 🚧📚 2021-07-15 14:24:41 -07:00
EntireTwix
98c7763ae2 🚧📚 2021-07-15 14:00:32 -07:00
EntireTwix
93cc7fcadf 🚧📚 2021-07-15 13:32:47 -07:00
EntireTwix
88b5253e02 🚧📚 2021-07-15 13:32:15 -07:00
EntireTwix
4cfa499127 🚧📚 2021-07-15 13:28:13 -07:00
EntireTwix
66fa73ed24 🐛 fixed lambda 2021-07-15 13:05:36 -07:00
EntireTwix
321efcd363 📚 rebranded as a in-game economies rather then minecraft specifically 2021-07-15 12:05:16 -07:00
William Katz
2d62f51006
🐛🔥🔒 possible safety concern if interior while auto saving
May corrupt as static, one thread could clear as the other is copying for example
2021-07-15 01:47:27 -07:00
William Katz
cc17c3f8d3
reverted commit 2021-07-15 01:42:01 -07:00
William Katz
559318d615
204 doesn't require JSON response 2021-07-15 01:39:27 -07:00
EntireTwix
e0b38be7e6 🐎:fire thread_local is not required as its only ever called by one thread 2021-07-15 01:25:36 -07:00
EntireTwix
0f128e04a0 reverted last commit oops 2021-07-15 01:15:51 -07:00
EntireTwix
3d8dc99874 🐎🔥 writer was faster without thread_local 2021-07-15 01:13:09 -07:00
EntireTwix
9c520d5e05 🐎 static thread_local when faster 2021-07-15 01:09:38 -07:00
EntireTwix
21abb82c76 cleaner solution to initial save file generation 2021-07-15 01:02:34 -07:00
EntireTwix
bf8ecccbb8 🔥 static not needed 2021-07-15 00:32:45 -07:00
EntireTwix
8fb7687d42 updated error message 2021-07-15 00:31:27 -07:00
EntireTwix
9223c520b1 clean solution found 2021-07-15 00:29:29 -07:00
EntireTwix
2599897788 🐛 fixed initial setup problem 2021-07-14 23:51:22 -07:00
EntireTwix
cbcfc1118c improved error handling 2021-07-14 23:42:23 -07:00
EntireTwix
9443fce984 updated build instructions 2021-07-14 23:05:20 -07:00
EntireTwix
ab1e154ab8 updated Save() and Load() paths 2021-07-14 23:02:34 -07:00
EntireTwix
30c4344055 updated default config and user paths 2021-07-14 23:02:11 -07:00
EntireTwix
35b9af952b 🔥 removed default users.json 2021-07-14 23:01:09 -07:00
EntireTwix
727e4ab4b8 FBE 2021-07-14 22:59:18 -07:00
EntireTwix
78f7f34f63 🔥 removed MAX_LOG_SIZE == 1 specific case 2021-07-14 22:59:04 -07:00
EntireTwix
5bc3511c43 🔥 removed MAX_LOG_SIZE == 1 specific case 2021-07-14 22:57:39 -07:00
EntireTwix
8d52d8f5e3 FBE 2021-07-14 22:56:24 -07:00
EntireTwix
0130f3c971 🎉 FBE 2021-07-14 22:56:10 -07:00
EntireTwix
e04dcc926d 🎨 changed SetBal format to match that of ImpactBal() 2021-07-14 00:31:14 -07:00
EntireTwix
a78afc314e SetBal and ImpactBal require valid name arg 2021-07-14 00:29:40 -07:00
EntireTwix
98215b9711 updated message 2021-07-14 00:22:03 -07:00
EntireTwix
23da8c686f 🎨 simplified with .back() 2021-07-14 00:21:49 -07:00
EntireTwix
15ef40b143 💡🔥 removing legacy comments 2021-07-14 00:05:47 -07:00
EntireTwix
732984a45d 💡🔥 removing legacy comments 2021-07-14 00:04:54 -07:00
EntireTwix
521f8614dd 🐛 AddUser() needs valid name check most of all 2021-07-13 23:52:08 -07:00
EntireTwix
6c99d32a64 🐛 MAX_LOG_SIZE == 1 wasnt updated 2021-07-13 21:04:33 -07:00
EntireTwix
4a56d57314 🐎 SendFunds made many times faster 2021-07-13 20:27:02 -07:00
EntireTwix
e5302af958 🔥 removed move constructor variant & adjusted to new log structure 2021-07-13 20:26:36 -07:00
EntireTwix
22d1e02460 🔥 removed move constructor variant 2021-07-13 20:26:15 -07:00
EntireTwix
8935b0cb4d 🔥 removed uneeded constructor 2021-07-13 20:25:58 -07:00
EntireTwix
e112468395 🐎 changed log structure from vector to deque 2021-07-13 20:25:41 -07:00
EntireTwix
fa1a9e6728 🔥 remove moved operations as they werent being utilized 2021-07-13 20:25:02 -07:00
EntireTwix
91aa848d0b 🔥 removed now irrelevant move operations 2021-07-13 20:24:17 -07:00
William Katz
f183235b94
updated to reflect recent commits 2021-07-13 18:41:10 -07:00
EntireTwix
bafb4b801d 🐎 DelSelf optimization 2021-07-13 18:30:24 -07:00
EntireTwix
d949783828 🐎🔥 inlined ValidUsername & removed GetChangedState() 2021-07-13 18:30:04 -07:00
EntireTwix
0ed5d5342b 🐎 inlined ValidUsername() && 🔥 removed GetChangeState() && 🐎 tweaked functions to include ValidUsername() && DelSelf() 2021-07-13 18:28:49 -07:00
EntireTwix
6e8b3357c9 🐎 inlined ValidUsername() 2021-07-13 18:26:52 -07:00
EntireTwix
a65224d39e 🐎🚚 moved shared lock to decrease scope accurately 2021-07-13 16:31:39 -07:00
EntireTwix
0954a76b6a 🔥 removed legacy constructor 2021-07-12 22:03:12 -07:00
EntireTwix
0f3a89b770 🎨 renamed auth input var 2021-07-12 21:41:03 -07:00
EntireTwix
a46801daea 🎨 style changes 2021-07-12 21:35:52 -07:00
EntireTwix
c94c19cbe1 🐎 made GetLogs() return move rather then const ref 2021-07-12 21:34:21 -07:00
EntireTwix
2f699e70c8 AdminChangePass must return when success 2021-07-12 21:29:27 -07:00
EntireTwix
df5dae02d0 AdminChangePass must return when success 2021-07-12 21:29:12 -07:00
EntireTwix
b2741aa276 🐛 changed some functions that previously returned true 2021-07-12 20:59:49 -07:00
EntireTwix
9b573ed7c3 🐛 JSON error responses werent strings 2021-07-12 20:55:07 -07:00
EntireTwix
6f8475ad1d 🔥 removed GEN_BODY and improved error responses of JSON parsing functions 2021-07-12 20:51:37 -07:00
William Katz
b2f306aee5
default snapshot value set to "null" 2021-07-12 17:23:43 -07:00
William Katz
66b200be27
🐛 empty log responds with ']' 2021-07-12 17:22:41 -07:00
William Katz
eb282de108
🐛 RETURN_ON_DEL should return bool 2021-07-12 17:16:25 -07:00
EntireTwix
c2d8742138 🐛 bad logic for name size 2021-07-12 16:23:30 -07:00
William Katz
16d26d1901
🐎🐛 fixed name specs and replaced function calls 2021-07-12 16:14:56 -07:00
William Katz
70d0374dd7
🎨 simplified to islower 2021-07-12 16:11:46 -07:00
William Katz
a2e0149606
🎨 formatting 2021-07-12 16:09:50 -07:00
William Katz
31f8a67dfb
🔥 removed legacy benchmarking macros 2021-07-12 15:48:27 -07:00
William Katz
7be15963d0
🔥🐎 removed jsoncpp from API properties 2021-07-12 15:45:37 -07:00
William Katz
f0c8920da1
Merge pull request #29 from Expand-sys/Refractor
missing docker files
2021-07-12 15:03:21 -07:00
Expand-sys
9318314d0c
Merge branch 'EntireTwix:Refractor' into Refractor 2021-07-13 08:00:06 +10:00
Expand-sys
8217bb2360 this done but needs twixie boi to merge 2021-07-13 07:56:34 +10:00
Expand-sys
495403864f pulling from github repo now so only docker file needed 2021-07-13 07:50:18 +10:00
Expand-sys
03d9c2aace Merge branch 'Refractor' of https://github.com/Expand-sys/CCash into Refractor 2021-07-13 07:34:11 +10:00
Expand-sys
c63fab572f pushing files needed for docker 2021-07-13 07:32:25 +10:00
William Katz
40bf5a22b0
Typo 2021-07-12 03:47:16 -07:00
William Katz
8428f7e71c
Update implementation.md 2021-07-12 03:45:57 -07:00
William Katz
4f27fd3d23
Update implementation.md 2021-07-12 03:45:43 -07:00
William Katz
dc85a3211a
Merge pull request #28 from Expand-sys/patch-1
slight fix on deployment commands
2021-07-12 02:37:04 -07:00
EntireTwix
2b28822239 🐎🎨 re-arranged function control flow 2021-07-11 20:38:39 -07:00
EntireTwix
4b6c71354f 🎨 RESPOND_TRUE related functions return 204 now 2021-07-11 15:38:23 -07:00
EntireTwix
8a23c8fa00 ImpactBal() now responds with new balance 2021-07-11 15:32:03 -07:00
EntireTwix
94e6b3da44 🐛 changed from =default 2021-07-11 01:55:39 -07:00
Expand-sys
c258f6ec86
slight fix on deployment commands 2021-07-11 18:49:16 +10:00
EntireTwix
f7dbd4c3e0 🐎 made logs copy construct from thread_local 2021-07-11 00:55:24 -07:00
EntireTwix
4b7ef754c0 updated README redirect in preperation of release 2021-07-10 23:08:29 -07:00
EntireTwix
72d57ce118 updated API list 2021-07-10 22:51:57 -07:00
EntireTwix
d5a7cf0481 📚🐛 fixed link 2021-07-10 22:46:03 -07:00
EntireTwix
b625e79c48 🎨 bootup output changes 2021-07-10 22:43:00 -07:00
EntireTwix
52bc5eeffb 📚 correction 2021-07-10 22:36:18 -07:00
EntireTwix
7145e66103 more memory usage info 2021-07-10 22:29:30 -07:00
EntireTwix
dd66144a3b memory usage info 2021-07-10 22:27:25 -07:00
EntireTwix
8c97d19330 🐛 I made a 0iq mistake 2021-07-10 21:49:24 -07:00
EntireTwix
8a6f9f2fce 🚚 moved simdjson header to User.h 2021-07-10 21:34:54 -07:00
EntireTwix
9927bd8217 🐛🔥 fixed logs 2021-07-10 21:34:19 -07:00
EntireTwix
8063a344aa 🐎🔥 removed jsoncpp from GetLogs() solution 2021-07-10 21:23:28 -07:00
EntireTwix
36e2f6301f 🐎 noexcept constructors 2021-07-10 20:01:05 -07:00
EntireTwix
6599f47dcc 🔥 removed INLINE macro 2021-07-10 20:00:47 -07:00
EntireTwix
3a44c0b065 🔥racehorse: temporary resp variable was unessasary 2021-07-10 19:14:15 -07:00
EntireTwix
c1587f9e46 🐎 valid name/pass check before vpass call 2021-07-10 18:56:58 -07:00
EntireTwix
518c1b1203 🎨 made save results from Save() 2021-07-10 12:09:01 -07:00
EntireTwix
f87ec947b6 using std::optional for 204 responses 2021-07-10 11:49:09 -07:00
EntireTwix
cfdb2fe829 updated docs 2021-07-10 10:22:56 -07:00
EntireTwix
82312b8702 🔥🐎 memset no longer needed 2021-07-10 09:59:37 -07:00
EntireTwix
c54f75a909 🐎 result_buffer is faster when local 2021-07-10 09:56:09 -07:00
EntireTwix
b91e928286 🐎 max base64 header size calculated compile time based on max name 2021-07-09 21:59:27 -07:00
EntireTwix
5a6a4180a0 🐛 nullptr isnt valid 2021-07-09 21:52:59 -07:00
EntireTwix
2d8cb3ee28 🐎 made resp construct a static thread_local again 2021-07-09 21:38:17 -07:00
EntireTwix
13d66b537c 🐎🚚 resp is faster when local 2021-07-09 21:35:01 -07:00
EntireTwix
074d024d77 🔥 removing static thread_local for temporary name/pass _val 2021-07-09 21:27:03 -07:00
EntireTwix
e0c79f980d 🐎 reverted changes after benchmarking 2021-07-09 21:19:34 -07:00
EntireTwix
6225083a06 🔥 removed legacy GEN_BODY 2021-07-09 21:06:27 -07:00
EntireTwix
408ea473d5 🐎 made each endpoint share the same name/pass intrusion strings 2021-07-09 21:04:01 -07:00
EntireTwix
386a140255 🐎🔨 modified endpoints to better adhere to JSON API conventions 2021-07-09 19:51:34 -07:00
EntireTwix
1f0a3dc28d 🐎🔨 modified endpoints to better adhere to JSON API conventions 2021-07-09 19:51:26 -07:00
EntireTwix
2d7d29372c 🔥🐎 changed local array to static thread_local buffer 2021-07-09 18:30:34 -07:00
EntireTwix
2e991da613 🔥🐎 changed local array to static thread_local buffer 2021-07-09 18:30:19 -07:00
EntireTwix
db5a54175c 🐛 fixed buffer size 2021-07-09 18:13:53 -07:00
EntireTwix
2fe00e05de 📚🚧 docs 2021-07-09 16:44:38 -07:00
EntireTwix
71e0915c2a 📚🚧 docs 2021-07-09 16:42:26 -07:00
EntireTwix
50a4e49452 🚚 renamed GetLog to GetLogs 2021-07-09 16:42:16 -07:00
EntireTwix
c7e2794e56 GetLogs() func doesnt compile when toggled off 2021-07-09 16:41:56 -07:00
EntireTwix
b60b6293aa 📚🚧 docs 2021-07-09 15:42:06 -07:00
EntireTwix
ba014df089 📚🚧 docs 2021-07-09 15:41:44 -07:00
EntireTwix
5b7d4b9af8 📚🚧 docs 2021-07-09 15:37:58 -07:00
EntireTwix
7d61ee5f83 📚🚧 docs 2021-07-09 15:26:59 -07:00
EntireTwix
a46adc28f9 refined a bit 2021-07-09 15:24:19 -07:00
EntireTwix
39fb5e96a1 📚🚧 docs 2021-07-09 15:24:00 -07:00
EntireTwix
7803c5e1e5 🐎 static thread_local negatively effects BankResponse 2021-07-09 00:45:55 -07:00
EntireTwix
f2b5385e92 🐎 made const ref 2021-07-09 00:43:25 -07:00
EntireTwix
1d826fe96e 🐛 toResponse is also impacted by filter thread_local bug 2021-07-09 00:42:30 -07:00
EntireTwix
18452fdf1e 🐎 noexcept 2021-07-09 00:30:07 -07:00
EntireTwix
dc6c3d70a0 🔨 made str_intrusion.h into a wrapper 2021-07-09 00:07:45 -07:00
EntireTwix
1d6bbb35bf 🐛 static thread_local in filters cause highly incorrect responses 2021-07-09 00:06:49 -07:00
EntireTwix
6e57178dc8 🐛 add trans was skipping ChangeOn() when full 2021-07-08 20:42:26 -07:00
EntireTwix
b1f0aad79e 🐛 ImpactBal accepts Int64 not UInt64 2021-07-08 16:39:54 -07:00
EntireTwix
a657c9d6b2 🔥 remembered why I removed GetChangeState() check 2021-07-08 16:14:52 -07:00
EntireTwix
6b11a9dadc str_intrusion source 2021-07-08 14:59:52 -07:00
EntireTwix
b8e88ad1f5 🚚 moved inline into config file 2021-07-08 14:59:30 -07:00
EntireTwix
16494f971e 🎨 formatting 2021-07-08 14:58:58 -07:00
EntireTwix
175976e796 string move overload 2021-07-08 14:58:30 -07:00
EntireTwix
da89d390ea 🔨 using str_intrusion.h to write to private string data 2021-07-08 14:58:03 -07:00
EntireTwix
053c20130e 🐎 static filter pointers 2021-07-08 03:01:22 -07:00
EntireTwix
fd6d085ae5 🐎 thread_local 2021-07-08 03:00:57 -07:00
EntireTwix
805a7d05b3 🐎 thread_local 2021-07-08 02:59:27 -07:00
EntireTwix
35ab4d9492 🔨 simdjson 2021-07-08 02:59:11 -07:00
EntireTwix
22c99cfbfb 🐎🔨 thread_local & simdjson 2021-07-08 02:58:55 -07:00
EntireTwix
3a39a2bf67 Merge branch 'Refractor' of https://github.com/EntireTwix/CCash into Refractor 2021-07-08 02:24:30 -07:00
EntireTwix
7e1ab2a38b <array> required for base64 buffer 2021-07-08 02:24:09 -07:00
EntireTwix
96f9351fb6 <array> required for base64 buffer 2021-07-08 02:23:26 -07:00
EntireTwix
91523ca6a5 🐎 static thread_local changes 2021-07-08 02:22:59 -07:00
EntireTwix
dba161c42c simdjson for requests/responses 2021-07-08 02:21:56 -07:00
EntireTwix
6e688f1385 🔥 removed iostream header leftover from debugging 2021-07-08 02:21:07 -07:00
EntireTwix
826db0baef 🚚 moved xxhash back from submodule to header 2021-07-08 02:20:44 -07:00
EntireTwix
6b481802e5 🔥 reverted last commit 2021-07-07 16:41:05 -07:00
EntireTwix
b18ec4e26d 🐛 fixed last commit -m 2021-07-07 16:40:03 -07:00
EntireTwix
a1df11eeeb 🐛 fixed last commit -m 2021-07-07 16:37:50 -07:00
EntireTwix
51a9ab8ff8 🐎 response is always true or false so to_string is slower 2021-07-07 16:30:28 -07:00
EntireTwix
9ee4f7ab88 🐎🚚 moved CORS to bank_api.cpp and cached RESPOND_TRUE 2021-07-07 16:14:54 -07:00
EntireTwix
85e3dc038c NumOfLogs() 2021-07-07 16:13:31 -07:00
EntireTwix
d649613d2e Merge branch 'Refractor' of https://github.com/EntireTwix/CCash into Refractor 2021-07-07 16:13:06 -07:00
EntireTwix
bb6b2f6c44 NumOfLogs() 2021-07-07 16:12:59 -07:00
William Katz
4944655af9
🎨 made isntructions more clear 2021-07-07 14:39:41 -07:00
EntireTwix
b0fdfc5f4f 🐎 checking if balance copied is non zero before modify call 2021-07-07 14:33:34 -07:00
EntireTwix
bd87a14131 🔥🐎 simplified 2021-07-07 03:14:51 -07:00
EntireTwix
6af072cf66 updated name requirements to conform with minecraft names 2021-07-07 03:11:55 -07:00
EntireTwix
23b6362d91 🐛 fixed from \"true\"->true 2021-07-07 03:06:58 -07:00
EntireTwix
bb7bd5daab 🎨 output allignment 2021-07-07 02:44:30 -07:00
EntireTwix
9fabf137f1 made RESPOND_TRUE use the custom BankResponse response 2021-07-07 02:44:11 -07:00
EntireTwix
f4f28fa92f 🐛 changed JsonFilter saving to body to setting parameter 2021-07-07 02:21:05 -07:00
EntireTwix
e3210f7337 🐛 undeflow check 2021-07-07 01:42:41 -07:00
EntireTwix
0c518c4ede fixed allignment of text 2021-07-06 22:48:22 -07:00
EntireTwix
e9443ee48d fixed allignment of text 2021-07-06 22:47:22 -07:00
EntireTwix
812ffcd5a0 API verison readout at launch 2021-07-06 22:46:05 -07:00
EntireTwix
a0307f211d updated benchmark 2021-07-06 22:07:06 -07:00
EntireTwix
2681ca86c2 🐛 fixed error messages for filters 2021-07-06 22:00:43 -07:00
EntireTwix
dedff14e7e 🐛🎨 fixed filters reliance on toResponse for bank responses crashing 2021-07-06 21:53:32 -07:00
EntireTwix
e02120b6f2 🔥 fucky wuck removed 2021-07-06 21:37:19 -07:00
EntireTwix
e3e4059c26 🐎 changed filter order 2021-07-06 21:14:54 -07:00
EntireTwix
e502f3ce1f 🔥🐎 made initial value compile time 2021-07-06 21:12:16 -07:00
EntireTwix
6dbb9fd98a 🔥🎨 replaced template specializations with class instaniations 2021-07-06 21:11:45 -07:00
EntireTwix
18b7923d7f 🐛 fixed testing state 2021-07-06 20:43:22 -07:00
EntireTwix
5ab0f89e89 🐎 noexcept and new constructor 2021-07-06 20:29:27 -07:00
EntireTwix
80cc3a99cf 🚧🐎 preparing to use FBE, in the meantime its 99% faster 2021-07-06 20:29:00 -07:00
EntireTwix
09911d5496 🚧🐎 preparing to use FBE, in the meantime its 99% faster 2021-07-06 20:28:37 -07:00
EntireTwix
4b5e5d930c 🐎 noexcept and new constructor 2021-07-06 20:27:52 -07:00
EntireTwix
67a3d02c82 🔥 cleaning pre_log changes 2021-07-06 19:04:57 -07:00
EntireTwix
30801e6730 🐛 fixed last commit 2021-07-06 19:03:59 -07:00
EntireTwix
15c648d6fa 🐛 fixed last commit 2021-07-06 19:03:14 -07:00
EntireTwix
bf5c2fde33 🐛 fixed last commit 2021-07-06 19:02:23 -07:00
EntireTwix
7ad83bfb63 🐛 fixed last commit 2021-07-06 19:01:06 -07:00
EntireTwix
2237d7a875 🔥 removed preallocting log functionality 2021-07-06 18:54:53 -07:00
EntireTwix
73ebb6e5bd 🔥 removed preallocting log functionality 2021-07-06 18:54:31 -07:00
EntireTwix
ff89efe4fc 🎉 BankResponse struct 2021-07-06 18:52:27 -07:00
EntireTwix
f431d8bcda 🔥racehorse: jsoncpp removed! 2021-07-06 18:51:56 -07:00
EntireTwix
14618ac991 added hashing to benchmark 2021-07-06 15:16:43 -07:00
EntireTwix
c7e5b68144 added hashing to benchmark 2021-07-06 15:13:58 -07:00
EntireTwix
28dadac225 added hashing to benchmark 2021-07-06 15:13:40 -07:00
EntireTwix
448149e60d 🎨fire: used custom HTTP response in filters 2021-07-06 15:05:03 -07:00
EntireTwix
f84d48e624 GetLogs isnt in benchmark if disabled 2021-07-06 02:15:42 -07:00
EntireTwix
2d186afa94 📚 simplified Admin Auth description 2021-07-06 02:13:36 -07:00
EntireTwix
46fcb1f443 🐛 Max log 1 optimizations fixed 2021-07-06 02:12:38 -07:00
EntireTwix
99f35a11df 🐛 Max log 1 optimizations fixed 2021-07-06 02:09:53 -07:00
EntireTwix
ae219af90e 🐛 fixed NumOfLogs if logs disabled 2021-07-06 02:04:44 -07:00
EntireTwix
cf580ae876 🐎🔥 std::move was not required 2021-07-05 19:49:51 -07:00
EntireTwix
c82a90f054 🐛 switched conditional oops 2021-07-05 19:42:35 -07:00
EntireTwix
9fce1fd083 🎨 renamed GetLog->GetLogs 2021-07-05 19:34:05 -07:00
EntireTwix
392708dfcc :update: replaced add/sub bal with impact balg 2021-07-05 19:33:16 -07:00
EntireTwix
cca2bf6216 🎨 uniform naming 2021-07-05 18:55:16 -07:00
EntireTwix
99af2c02ab 🎨 uniform naming 2021-07-05 18:52:58 -07:00
EntireTwix
c29abc34e0 🐛 fixed last commit 2021-07-05 18:49:41 -07:00
EntireTwix
597a710e2b made save function absolute 2021-07-05 18:49:13 -07:00
EntireTwix
94fce9cd1f interupt close now outputs if saved similiar to auto-save 2021-07-05 18:46:36 -07:00
EntireTwix
4c3b521966 🐛 as amount can be negative now, conditional must change 2021-07-05 17:43:25 -07:00
EntireTwix
cb06dd31dd 2021-07-05 17:30:20 -07:00
EntireTwix
297b184a11 🎨🔥 reduced Sub/Add Bal() to ImpactBal() 2021-07-05 17:27:18 -07:00
EntireTwix
e9ccf6b227 🐛 path typo 2021-07-05 17:19:54 -07:00
EntireTwix
da2074859e 🎨🔥 merged admin filter with user filter as template arg 2021-07-05 17:11:24 -07:00
EntireTwix
6bc6c78ed7 fixed benchmark 2021-07-05 16:30:54 -07:00
EntireTwix
a98a813189 fixed benchmark 2021-07-05 16:27:26 -07:00
EntireTwix
1a7a3e50ed updated graph 2021-07-05 16:27:01 -07:00
EntireTwix
9634d95d67 🐛🔨 forgot to update path 2021-07-05 16:15:33 -07:00
EntireTwix
76fc8084ce 📚 improved graph 2021-07-05 16:15:16 -07:00
EntireTwix
fd2efb3ddf updated AddUser() call in GetBal() test 2021-07-05 16:02:32 -07:00
EntireTwix
c8894e7d31 📚 GetBal() graph 2021-07-05 16:01:32 -07:00
EntireTwix
6926cf8791 🔥🐛 left a legacy cout in 2021-07-05 15:54:32 -07:00
EntireTwix
ff01ff5189 📚 cert message 2021-07-05 14:57:27 -07:00
EntireTwix
d25ff09bdf 🎨 simplified by specializing toResponse() 2021-07-05 14:52:31 -07:00
EntireTwix
f6a6c23fc3 🔥 removed ping transformed api version into api properties 2021-07-05 13:54:30 -07:00
EntireTwix
a37742193f 📚 moved buttons 2021-07-05 02:41:43 -07:00
EntireTwix
aece911b90 📚 moved buttons 2021-07-05 02:40:48 -07:00
EntireTwix
1f5f052de1 📚 next and previous page buttons 2021-07-05 02:38:57 -07:00
EntireTwix
a5d06bfa70 📚 next and previous page buttons 2021-07-05 02:36:27 -07:00
EntireTwix
1f39a353e5 📚🚧 working on docs 2021-07-05 02:26:16 -07:00
EntireTwix
e7f61d38ee 🚧 added GetLog() 2021-07-05 01:15:40 -07:00
EntireTwix
44a916b09f 🚧 added GetLog() 2021-07-05 01:15:08 -07:00
EntireTwix
7abca3126b 🎨 for conformity, GetLogs always returns 64 bit time_t 2021-07-05 01:13:33 -07:00
EntireTwix
bb0f3b642d 📚🚧 working on endpoints 2021-07-05 00:54:51 -07:00
EntireTwix
53524e8409 📚🚧 working on endpoints 2021-07-05 00:54:13 -07:00
EntireTwix
4976d5bca6 📚🚧 working on endpoints 2021-07-05 00:50:03 -07:00
EntireTwix
f0772ed6f0 📚🚧 working on endpoints 2021-07-05 00:49:14 -07:00
EntireTwix
9a62f9e7ed 📚🚧 working on endpoints 2021-07-05 00:45:59 -07:00
EntireTwix
2d464df178 📚🚧 working on endpoints 2021-07-05 00:45:13 -07:00
EntireTwix
6eb02a8288 🐛🎨 fixed filter organization 2021-07-05 00:44:53 -07:00
EntireTwix
97fd39b1d4 🐎 body only set if method needs it 2021-07-04 23:42:18 -07:00
EntireTwix
b310c8ec2b 🐛🐎 fixed last commit and made faster 2021-07-04 23:18:55 -07:00
EntireTwix
84ecfac199 📚 fixed 2021-07-04 22:53:27 -07:00
EntireTwix
5275028fd6 🐛 fixed user/admin filter std::string_view fuckery 2021-07-04 22:48:24 -07:00
EntireTwix
27f0c951ad 🐛 typo 2021-07-04 21:02:24 -07:00
EntireTwix
0eea88e75c updated contributions 2021-07-04 20:43:09 -07:00
EntireTwix
8342c461da 🐛 added cash_config.hpp back to gitignore 2021-07-04 20:42:37 -07:00
William Katz
92d629758b
Fixed Docker Package
🐛
2021-07-04 20:41:06 -07:00
Expand-sys
cef439ef8b
Merge branch 'EntireTwix:Refractor' into Refractor 2021-07-05 13:38:28 +10:00
Expand-sys
d39247a3b4 dockerfile changes 2021-07-05 13:37:21 +10:00
EntireTwix
3edd25dbe8 🐎 optimized for when log == 1 2021-07-04 20:34:49 -07:00
EntireTwix
6026e6aad5 📚🚧 working on docs 2021-07-04 20:18:34 -07:00
EntireTwix
84ebf306e2 📚🚧 working on docs 2021-07-04 19:04:26 -07:00
EntireTwix
1bc27efbba 📚🚧 working on docs 2021-07-04 18:58:33 -07:00
EntireTwix
b9baf2dd78 📚🚧 working on docs 2021-07-04 18:53:52 -07:00
EntireTwix
73d0af5ac4 📚🚧 working on docs 2021-07-04 18:51:50 -07:00
EntireTwix
3b2e57edde 📚 replaced contribs link with file 2021-07-04 18:50:14 -07:00
EntireTwix
317233be67 changed redirect adress 2021-07-04 18:18:16 -07:00
EntireTwix
3537504bfc 📚 filling in docs 2021-07-04 18:15:45 -07:00
EntireTwix
65a204022b 📚 filling in docs 2021-07-04 18:07:37 -07:00
EntireTwix
0a246bd5bb 📚 filling in docs 2021-07-04 17:52:07 -07:00
EntireTwix
c0b785f5f1 📚 filling in docs 2021-07-04 17:51:38 -07:00
EntireTwix
4801cbd3bf 📚 filling in docs 2021-07-04 16:41:18 -07:00
EntireTwix
a8c041249c 📚 filling in docs 2021-07-04 16:34:03 -07:00
EntireTwix
79932f5223 📚 filling in docs 2021-07-04 16:33:20 -07:00
EntireTwix
01f7be1d5c 📚 filling in docs 2021-07-04 14:32:24 -07:00
EntireTwix
8e92dccd88 📚 filling in docs 2021-07-04 14:16:21 -07:00
EntireTwix
5f745ee03b 📚 filling in docs 2021-07-04 13:37:07 -07:00
EntireTwix
86d4b96b7b 🐛 fixed formatting 2021-07-04 13:12:48 -07:00
EntireTwix
34d48bd235 updated docs 2021-07-04 13:11:33 -07:00
EntireTwix
6a8b5da869 🐛 always init ints kids 2021-07-04 03:46:41 -07:00
EntireTwix
b6344da31d 💄 NumOfUsers() & NumOfLogs() for loading output 2021-07-04 03:33:17 -07:00
EntireTwix
c9562d26c7 SubBal() 2021-07-04 03:20:42 -07:00
EntireTwix
e81a7b281e SubBal() 2021-07-04 03:12:17 -07:00
EntireTwix
e87ab53a8a AddBal() 2021-07-04 03:05:42 -07:00
EntireTwix
b0ba114445 🔥 default is k200 2021-07-04 02:58:53 -07:00
EntireTwix
d6a55652ca AddBal 2021-07-04 02:48:09 -07:00
EntireTwix
77c6923765 🐛 self delete uses name as param 2021-07-04 02:36:23 -07:00
EntireTwix
62d68924af added generated ccash_config.hpp to .gitignore 2021-07-04 02:33:22 -07:00
EntireTwix
65d21848b3 🚧 help redirects to repo help docs 2021-07-04 02:32:41 -07:00
EntireTwix
b9af380b64 🐎 very slight improvement 2021-07-04 02:24:38 -07:00
EntireTwix
6402ad300c 🐛 fixed Json Filter 2021-07-04 02:14:19 -07:00
EntireTwix
ea35a04b66 🎨 made vpass and admin/vpass POST 2021-07-04 01:57:01 -07:00
EntireTwix
29044d697c 🐎 references rather then copy 2021-07-04 01:32:03 -07:00
EntireTwix
46b48b1d6f 🚧 working on 2021-07-04 01:31:43 -07:00
EntireTwix
617b52ac93 Accept Filter 2021-07-04 01:27:12 -07:00
EntireTwix
f0a296d97b Accept Filter 2021-07-04 01:26:44 -07:00
EntireTwix
8b30588d8f 🐎 made RESPOND_TRUE cached 2021-07-04 01:24:36 -07:00
EntireTwix
89e4da34bf 🚚 moved CORS back 2021-07-04 00:48:43 -07:00
EntireTwix
85ee2167ff 🚚 moved CORS back 2021-07-04 00:47:35 -07:00
EntireTwix
244852eb45 updated benchmark 2021-07-03 22:31:12 -07:00
EntireTwix
239e8007e9 🔥🎨 simplified by using only one save_lock 2021-07-03 19:45:52 -07:00
EntireTwix
a561742347 🎨 simplified DelUser() 2021-07-03 19:10:32 -07:00
EntireTwix
029a10f1bc 🎨 simplified 2021-07-03 18:48:42 -07:00
EntireTwix
e157586557 🐛 fixing how Conservative saving flag impacts code 2021-07-03 18:35:28 -07:00
EntireTwix
8c373d6f19 🐛 fixed cmake 2021-07-03 18:32:08 -07:00
EntireTwix
f04ca463fe 🔥 reverted noexcept as drogon doesnt like it 2021-07-03 17:48:11 -07:00
EntireTwix
5c1a9264d3 🐎 noexcept 2021-07-03 17:43:59 -07:00
EntireTwix
b90552d0d4 🐛🐎 noexcept and fixed DelUser 2021-07-03 17:43:46 -07:00
EntireTwix
7c0b4f48bd 🚚 moved CORS header 2021-07-03 17:31:27 -07:00
EntireTwix
007f7098ce fixed 2021-07-03 17:17:03 -07:00
EntireTwix
b2fcd69a57 🔥 made API version not setuable by CMake 2021-07-03 15:00:35 -07:00
EntireTwix
ee8bd88c96 🐛 fixed docs 2021-07-03 14:52:39 -07:00
EntireTwix
2d9fc33835 base64 2021-07-03 14:47:35 -07:00
EntireTwix
aecdea522d 🚧 building docs 2021-07-03 14:44:26 -07:00
EntireTwix
770027473e more flags in CMake 2021-07-03 11:57:38 -07:00
EntireTwix
0b59e273f0 🐛 multiple methods didnt toggle change flag 2021-07-03 11:45:39 -07:00
EntireTwix
5ac2dcb55b 🎨 Me->me 2021-07-03 02:06:23 -07:00
EntireTwix
3f8fad0dbf 🚧 docs 2021-07-03 02:01:55 -07:00
EntireTwix
e7643bc793 🐛 API version should not be a bool 2021-07-03 01:43:43 -07:00
EntireTwix
f3c3c47e73 API Version Endpoint 2021-07-03 01:41:24 -07:00
EntireTwix
5fe22d8635 made multiple flags configurable from CMake 2021-07-03 01:33:32 -07:00
EntireTwix
ca6187fffc 🐛 setbal was using NAME_PARAM as user 2021-07-03 01:27:07 -07:00
EntireTwix
88e5cfc3d3 🔥 removed comments 2021-07-03 01:06:59 -07:00
EntireTwix
fd657dd9bf 🔥🐎 password never initilized if username isnt admin 2021-07-03 01:06:49 -07:00
EntireTwix
1b950ce0c0 🐛 fixed last commit 2021-07-03 00:46:40 -07:00
EntireTwix
7d1ec6d634 🐛 typo 2021-07-03 00:40:24 -07:00
EntireTwix
0e5836b777 🎨🐎 multi threaded flag for conditional compiling 2021-07-03 00:39:42 -07:00
EntireTwix
10537fb942 🎨 moved ChangeState() 2021-07-02 23:46:16 -07:00
EntireTwix
72cbbd5494 🐎 move overload 2021-07-02 23:45:50 -07:00
EntireTwix
1c5f2e1ae6 🐎 improved SendFunds() 2021-07-02 23:33:17 -07:00
EntireTwix
5ffd655de5 🐛 prettier messed with stuff 2021-07-02 23:10:23 -07:00
EntireTwix
3a3b168e49 🐛 prettier messed with stuff 2021-07-02 23:09:12 -07:00
EntireTwix
6eacdb6d1e 🐛 removed typo 2021-07-02 22:42:53 -07:00
EntireTwix
fe98e73319 🔥🎨🐎 removed substr_view after learning string_view::substr is O(1) 2021-07-02 22:42:24 -07:00
EntireTwix
89ca26b9e6 🔥🎨🐎 removed substr_view after learning string_view::substr is O(1) 2021-07-02 22:42:09 -07:00
EntireTwix
69ff81c727 🐎 Transaction names moved in 2021-07-02 22:41:40 -07:00
EntireTwix
ec9944d80e 🐎 made add user moved in 2021-07-02 22:37:01 -07:00
EntireTwix
c63bc137c4 conditional compiling no certs when getlogs removed 2021-07-02 22:36:40 -07:00
EntireTwix
290d6da0ef 🔥🎨🐎 removed substr_view after learning string_view::substr is O(1) 2021-07-02 22:36:08 -07:00
EntireTwix
fc762871ff updated benchmark 2021-07-02 19:15:49 -07:00
EntireTwix
55d71c7a6d changed save location of config 2021-07-02 19:15:11 -07:00
EntireTwix
c51074d47c 🔥 changed defaults 2021-07-02 19:06:07 -07:00
EntireTwix
f97915591a 🔥 to be generated 2021-07-02 19:05:44 -07:00
EntireTwix
aa71a9f538 configurable save locations in CMake 2021-07-02 19:04:07 -07:00
EntireTwix
1a77ca43dc 🎨 changed admin verification to be account name rather then password 2021-07-02 17:19:11 -07:00
EntireTwix
c9da3eab04 base64 2021-07-02 17:18:37 -07:00
EntireTwix
e7f7f0f698 🎨 changed uint64_t -> XXH64_hash_t 2021-07-02 00:04:05 -07:00
EntireTwix
88a3d79f9c 🐛 removed extremely low chance of overflow 2021-07-01 23:58:27 -07:00
EntireTwix
3e0efa780b 🐎 made noexcept 2021-07-01 23:29:57 -07:00
EntireTwix
d93786f4ff 🚚 moved hash function to seperate header 2021-07-01 23:29:22 -07:00
EntireTwix
00a3d0c075 base64 submodule 2021-07-01 23:28:22 -07:00
EntireTwix
d13100ccea base64 submodule 2021-07-01 23:28:14 -07:00
EntireTwix
9c467020d4 🐛 fixed last commit 2021-07-01 23:27:36 -07:00
EntireTwix
f19ed761e2 console ouput supported instruction sets 2021-07-01 23:27:09 -07:00
EntireTwix
541efad1ff Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-07-01 21:23:29 -07:00
EntireTwix
d3393e8084 🐛 fixed massive send without b_name existing 2021-07-01 21:18:12 -07:00
William Katz
f62465419e
🐛 massive bug 2021-06-30 16:53:23 -07:00
EntireTwix
60540f810f updated 2021-06-29 23:48:10 -07:00
EntireTwix
1cc1a41561 🚚 moved xxHashStringGen to bank.h 2021-06-29 23:43:10 -07:00
EntireTwix
1f49a9b79a setup xxhash as submodule build 2021-06-29 23:42:14 -07:00
EntireTwix
a00a98298a xxhash made submodule 2021-06-29 23:34:04 -07:00
EntireTwix
de694c6ebd admin change password 2021-06-29 22:35:05 -07:00
EntireTwix
766047dc07 🐎 slight simplification 2021-06-29 22:33:53 -07:00
EntireTwix
117bd33ca0 🐛 error on cast 2021-06-29 15:54:57 -07:00
EntireTwix
8d6921b70d added header 2021-06-29 15:54:39 -07:00
EntireTwix
c13164dde8 🐎 made phmap use xxhash as hashing 2021-06-29 15:06:18 -07:00
EntireTwix
58c16457cf changed endpoints and API_VERSION conditional 2021-06-29 12:58:56 -07:00
EntireTwix
2bed29edd0 🐎 march=native 2021-06-29 12:21:32 -07:00
EntireTwix
bec9538bc9 changed endpoints and API_VERSION conditional 2021-06-29 12:21:14 -07:00
EntireTwix
e8941d60cd 🔥🐎 cleaned up 2021-06-28 20:18:24 -07:00
EntireTwix
58e00e3b75 updated 2021-06-28 20:17:59 -07:00
EntireTwix
0e62dbe9ef finished Endpoint/Internal rewrite 2021-06-28 19:47:17 -07:00
EntireTwix
0c34bc3689 🐛 fixing last commit 2021-06-27 22:12:31 -07:00
EntireTwix
6e46cb8f7a 🐎 save_flag is not required if conservative saving is disabled 2021-06-27 21:49:42 -07:00
EntireTwix
23928235eb 🐎 slight include optimization 2021-06-27 21:47:42 -07:00
EntireTwix
d5490ebc56 made log settings Macros 2021-06-27 21:44:40 -07:00
EntireTwix
1adb23f5b8 🐎 GetLog() snapshot 2021-06-27 21:08:10 -07:00
EntireTwix
ba20e461f6 ChangeFlag class 2021-06-27 20:27:03 -07:00
EntireTwix
1ea1618228 🎨 simplified DelUser() 2021-06-27 19:38:06 -07:00
EntireTwix
541b912efe 🐛 fixed return on delete functionality 2021-06-27 19:33:27 -07:00
EntireTwix
3b1a459e18 🐛 fixed last commit 2021-06-27 19:30:16 -07:00
EntireTwix
6d6b55025b 🐛 fixed last commit 2021-06-27 19:29:36 -07:00
EntireTwix
113a765c14 added ChangesMade() to functions 2021-06-27 19:28:06 -07:00
EntireTwix
731132e719 🐎 performance changes 2021-06-27 18:57:27 -07:00
EntireTwix
1aa450e112 🐎 improved SetBal() 2021-06-27 18:10:38 -07:00
EntireTwix
1a434c6bcb SetBal() 2021-06-27 18:05:33 -07:00
EntireTwix
deae9fab7c 🐛 was set to 0 for testing 2021-06-27 17:55:04 -07:00
EntireTwix
3028c6153a 🎨 improved CONSERVATIVE_DISK_SAVE flags usage 2021-06-27 17:53:46 -07:00
EntireTwix
a4964d2742 🎨 moved macros 2021-06-27 17:43:17 -07:00
EntireTwix
482e8709a7 🎨 corrected RESPONSE_PARSE 2021-06-27 17:40:05 -07:00
EntireTwix
d92bc60e79 🎨 changed how API versions are handled 2021-06-27 17:35:31 -07:00
EntireTwix
d9986db962 🎨 changed how API versions are handled 2021-06-27 17:34:12 -07:00
EntireTwix
539df650ea API version compiler flag 2021-06-27 17:13:19 -07:00
EntireTwix
7dec3bea72 admin filter header 2021-06-27 17:10:51 -07:00
EntireTwix
371cd16e38 🐎 made admin vpass internal 2021-06-27 16:59:22 -07:00
EntireTwix
a32efe611f admin filter 2021-06-27 16:58:34 -07:00
EntireTwix
40863d5dda more descriptive outputs 2021-06-27 16:32:49 -07:00
EntireTwix
c8b7935329 🐛 fixed with new changepass 2021-06-27 13:04:47 -07:00
EntireTwix
dfdeba08bd 🐎 removed lambda args 2021-06-27 12:50:44 -07:00
EntireTwix
b64e562235 changed error status 2021-06-27 12:47:20 -07:00
EntireTwix
749d20880f changed structure 2021-06-27 11:34:14 -07:00
EntireTwix
faf63b0d4b changed structure 2021-06-27 11:33:46 -07:00
EntireTwix
893ca3884d 🐎 name is temporarily stored in body 2021-06-27 00:02:30 -07:00
EntireTwix
a4505b1408 :construction 2021-06-27 00:01:00 -07:00
EntireTwix
8eadc3e6d9 changed some constexpr flags to macros 2021-06-26 19:21:39 -07:00
EntireTwix
42ed5b3424 UserFilter for endpoints 2021-06-26 19:21:20 -07:00
EntireTwix
9a0e59c83a 🚧 converting functions 2021-06-26 19:20:41 -07:00
EntireTwix
dfaac069a8 🔥 removed thread argument in place of detecting CPU cores 2021-06-26 19:20:12 -07:00
EntireTwix
e88d699ea8 updated for new source files 2021-06-26 19:19:45 -07:00
EntireTwix
8c9fbcc6f5 updated for new function args 2021-06-26 19:19:23 -07:00
EntireTwix
714292309e 🔥 removed md files to be rewritten later 2021-06-26 13:24:58 -07:00
William Katz
48117b1834
Merge pull request #24 from LukeeeeBennett/autodeploy
Autodeploy
2021-06-24 14:43:50 -07:00
Luke Bennett
396d95f340 ci: add deploy workflow 2021-06-24 19:16:00 +01:00
EntireTwix
eff2d553f5 🔥 removed unused variable 2021-06-24 10:40:18 -07:00
EntireTwix
d8faf47801 changed comments 2021-06-24 10:35:18 -07:00
EntireTwix
85ffb7e1c3 changed comments 2021-06-24 10:34:28 -07:00
EntireTwix
6abca9b0f0 made constexpr rather then macro 2021-06-23 19:47:22 -07:00
EntireTwix
7bc0dd25d0 🐛 fixed Del/Admin Del users return to reserver functionality 2021-06-23 19:47:05 -07:00
William Katz
36ee1e6635
🔥 removed return on delete temporarily 2021-06-23 19:45:24 -07:00
EntireTwix
6161ca8d59 simplified changes saved 2021-06-23 18:51:10 -07:00
EntireTwix
7aadd63cd5 implementing change state saving 2021-06-23 18:36:39 -07:00
EntireTwix
57a0ab5d54 changed default 2021-06-23 18:15:56 -07:00
EntireTwix
f98975ae35 🐛 got change flag working 2021-06-23 18:15:42 -07:00
EntireTwix
72c5369b58 🔥 removed alg header 2021-06-23 18:15:28 -07:00
EntireTwix
992b8371d1 🐛 got change flag working 2021-06-23 18:14:45 -07:00
EntireTwix
2ea4d93c10 atomic flag 2021-06-23 17:17:13 -07:00
EntireTwix
9c426223e9 simplified 2021-06-23 17:16:55 -07:00
EntireTwix
c5f15fcd56 update 2021-06-23 15:41:59 -07:00
EntireTwix
33ff53de1d 🐛 corrected macro usage 2021-06-23 15:32:22 -07:00
EntireTwix
d8a840d052 changed default and added to comment 2021-06-23 15:28:50 -07:00
EntireTwix
dabcf1d311 updated comments 2021-06-23 15:24:59 -07:00
EntireTwix
839d7eb96b conservative saving 2021-06-23 15:24:00 -07:00
EntireTwix
cf036901bb conservative saving 2021-06-23 15:23:54 -07:00
EntireTwix
ac859f2c17 🐛 forgot time_val in constructor 2021-06-23 15:10:10 -07:00
EntireTwix
567a24231d simplified constructors 2021-06-23 14:30:47 -07:00
EntireTwix
6637f0042e 🐛 changed uint64 to time_t 2021-06-23 14:24:20 -07:00
EntireTwix
22d8001066 renamed bank_f->bank_api 2021-06-23 14:20:19 -07:00
EntireTwix
e2c657bf2d 🐎 supplemented chrono ms for ctime time() 2021-06-23 14:20:11 -07:00
EntireTwix
9be3333efb renamed bank_f->bank_api 2021-06-23 14:18:47 -07:00
Luke Bennett
a962917db0 refactor: rename deploy.yaml to build.yaml 2021-06-23 19:04:37 +01:00
Luke Bennett
58d5d3e28b Merge remote-tracking branch 'upstream/main' into autodeploy 2021-06-23 19:04:03 +01:00
Luke Bennett
1c2e0ff75a docs: movs docs to /docs, add deploy docs 2021-06-23 19:01:42 +01:00
EntireTwix
85cbff7a62 🐛 fixed previous commits 2021-06-23 10:17:21 -07:00
EntireTwix
29f9905b53 changed b arg to reference 2021-06-23 10:07:05 -07:00
EntireTwix
00b6c92a38 renamed BankF->api 2021-06-22 21:00:12 -07:00
EntireTwix
6f84d90f51 🔥 removed simdjson in pursuit of a serialization lib 2021-06-22 17:43:56 -07:00
EntireTwix
3905ec219a renamed BankF->api 2021-06-22 17:23:04 -07:00
EntireTwix
ec9b9f389d added simdjson 2021-06-22 17:22:27 -07:00
William Katz
3e79d4e7a3
Update README.md 2021-06-21 16:52:43 -07:00
William Katz
8698dd9570
Dev section 2021-06-21 16:52:22 -07:00
William Katz
7550e83169
Update README.md 2021-06-20 22:39:28 -07:00
EntireTwix
0b10a51a19 Return to Reserve Feature 2021-06-20 21:54:32 -07:00
EntireTwix
bc067bafe9 🐛 send funds wasnt logging correctly 2021-06-20 19:21:08 -07:00
EntireTwix
f48882d446 simplified 2021-06-20 13:25:53 -07:00
EntireTwix
f58813606d 🐎 slightly faster when logs arent full 2021-06-19 20:50:06 -07:00
EntireTwix
2dc1c0c369 🐎 6% faster sendfunds 2021-06-19 15:19:44 -07:00
EntireTwix
a08d53bf34 changed order of conditional 2021-06-19 14:28:48 -07:00
EntireTwix
31e08aeb97 🐎 made send funds 30% faster 2021-06-19 14:23:39 -07:00
EntireTwix
f2b7a563d9 🐎 made send funds 30% faster 2021-06-19 14:23:19 -07:00
EntireTwix
84f26a5ea5 removed reliance on save file 2021-06-19 12:25:04 -07:00
EntireTwix
694ebef4e3 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-19 12:23:17 -07:00
EntireTwix
96c6ac07d5 benchmarking program 2021-06-19 12:23:12 -07:00
William Katz
485c5f6442
Update README.md 2021-06-19 10:42:31 -07:00
EntireTwix
aa9f481fbe names can no longer contain spaces 2021-06-18 17:00:27 -07:00
EntireTwix
b4013a168f edited memory usage figure 2021-06-18 15:38:55 -07:00
EntireTwix
191c308561 moved Python API to done 2021-06-18 15:30:19 -07:00
EntireTwix
e07a393485 🐛 added JsonCast back 2021-06-18 13:50:47 -07:00
EntireTwix
0b9a8a1541 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-18 12:41:31 -07:00
EntireTwix
882311eb5f 🐛 forgot 2021-06-18 12:41:16 -07:00
William Katz
f541e16a4d
🔥 GEN_BODY is no longer needed 2021-06-18 12:22:11 -07:00
William Katz
04bf0c55e4
🐎 reduces json parsing to 0ns
json parsing used to be 75% of functions like GetBal's cost, but now its 0% as its just moved in and implicitly cast to Json::Value
2021-06-18 12:21:37 -07:00
William Katz
9f58dda6d2
Order 2021-06-18 10:48:19 -07:00
William Katz
ccc6a10dca
Order 2021-06-18 10:44:06 -07:00
William Katz
209d333240
Update .dockerignore 2021-06-18 09:20:21 -07:00
William Katz
78ca9dad02
Update README.md 2021-06-18 08:13:48 -07:00
William Katz
30a3a85431
Update README.md 2021-06-17 21:12:11 -07:00
William Katz
2e83194cb2
Merge pull request #21 from Expand-sys/patch-1
patch for ccashdeploy docker
2021-06-17 21:11:37 -07:00
Expand-sys
fd11a4d52a
patch for ccashdeploy docker 2021-06-18 12:37:32 +10:00
EntireTwix
315c0d934f hash comments 2021-06-16 22:44:00 -07:00
EntireTwix
e40aa29b59 🎨 formatting 2021-06-16 21:42:46 -07:00
EntireTwix
e681b4109d made user & config save configurable 2021-06-16 21:40:31 -07:00
William Katz
9a3a54c4ca
Update README.md 2021-06-16 20:25:58 -07:00
EntireTwix
abaf8a400a Project v Connected Service distinction 2021-06-16 20:20:31 -07:00
William Katz
c4303ccfa6
Update help.md 2021-06-16 11:11:30 -07:00
William Katz
b336781e9c
Update .dockerignore 2021-06-16 10:54:12 -07:00
William Katz
cc72f1e748
Merge pull request #20 from LukeeeeBennett/patch-1
ci: release docker image on main branch
2021-06-16 09:43:50 -07:00
Luke Bennett
7bf6b6c1e4
ci: release docker image on main branch 2021-06-16 12:02:28 +01:00
William Katz
6d35eee99f
Update README.md 2021-06-15 22:37:38 -07:00
William Katz
32b212b83b
Docker
[WIP] ci: add Dockerfile and deploy workflow
2021-06-15 22:36:21 -07:00
Luke Bennett
7152054edb
ci: CMD env vars, publish to GH packages 2021-06-16 02:04:07 +01:00
Luke Bennett
8cfb21203e
Merge remote-tracking branch 'upstream/main' into cicd 2021-06-16 01:11:03 +01:00
Luke Bennett
7637446362
chore: add .dockerignore 2021-06-16 01:10:49 +01:00
EntireTwix
a028b9a628 🐛 silly error 2021-06-15 13:21:21 -07:00
EntireTwix
153ff6e39d temp was extraneous 2021-06-15 13:16:18 -07:00
EntireTwix
39f5190e36 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-15 12:34:31 -07:00
EntireTwix
17cb1a0c23 int 64 cast json 2021-06-15 12:34:15 -07:00
William Katz
73c4a64666
Renamed CC ATM 2021-06-15 08:27:55 -07:00
William Katz
ad88f5842b
Update README.md 2021-06-15 08:07:22 -07:00
William Katz
b14ab979e8
Merge pull request #19 from STBoyden/patch-1
Update CC to ComputerCraft (Lua) in APIs.md
2021-06-15 08:05:48 -07:00
Samuel Boyden
d013abdf4c
Update CC to ComputerCraft (Lua) in APIs.md
So as to make it more explicit what language/usage it is.
2021-06-15 14:58:44 +01:00
William Katz
20de9805a9
Update README.md 2021-06-15 03:12:51 -07:00
William Katz
f768417753
Update APIs.md 2021-06-15 03:11:42 -07:00
Luke Bennett
fc8b8a9cb6
Merge remote-tracking branch 'upstream/main' into cicd 2021-06-15 11:04:45 +01:00
Luke Bennett
9d4688e5ed
ci: add Dockerfile and deploy workflow 2021-06-15 11:02:47 +01:00
William Katz
1f8df1e94c
Update README.md 2021-06-14 23:38:39 -07:00
William Katz
1b7a0159bb
Update help.md 2021-06-14 23:25:59 -07:00
William Katz
18645f4346
Update config.json 2021-06-14 23:25:23 -07:00
EntireTwix
3db06bf661 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-14 22:14:25 -07:00
EntireTwix
bd357db0ac admin wrong password removed 2021-06-14 22:14:16 -07:00
William Katz
8bffcb050d
Update README.md 2021-06-14 22:09:01 -07:00
William Katz
f59c0793ee
Update README.md 2021-06-14 22:08:23 -07:00
William Katz
706d304de8
Update services.md 2021-06-14 21:38:13 -07:00
William Katz
d0175c34b9
Homebrew deps in readme
docs(README): add homebrew deps
2021-06-14 21:25:29 -07:00
William Katz
00aea60eaa
Update users.json 2021-06-14 21:24:14 -07:00
EntireTwix
dedc62f0f7 turned some conditionals into turnary for code cleanliness 2021-06-14 18:49:17 -07:00
EntireTwix
79f388af72 fixed major sendfunds bug 2021-06-14 18:27:03 -07:00
Luke Bennett
59cc8a8b2a
docs(README): add homebrew deps 2021-06-14 22:23:52 +01:00
EntireTwix
2ccb18345f 🐛 warnings removed 2021-06-14 13:50:49 -07:00
EntireTwix
de14e2983a removed last commits console out 2021-06-14 11:04:06 -07:00
EntireTwix
ead2f87ab7 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-14 11:00:48 -07:00
EntireTwix
67a8642245 added ? to query param of setbal & sendfunds 2021-06-14 10:59:03 -07:00
William Katz
3d09ce58c4
Merge pull request #16 from LukeeeeBennett/patch-1
docs: fix param syntax and improve body desc
2021-06-13 14:07:28 -07:00
Luke Bennett
d99e8b1adf
docs: format help.md with prettier 2021-06-13 22:02:46 +01:00
Luke Bennett
4ce87f4aa1
docs(help): correct password as body explaination 2021-06-13 22:02:37 +01:00
Luke Bennett
ce16d5f5ae
docs: format help.md with prettier 2021-06-13 21:55:00 +01:00
Luke Bennett
a988dab361
docs(help): explain where log length is configured 2021-06-13 21:54:47 +01:00
Luke Bennett
d90f0dc9ba
docs: format help.md with prettier 2021-06-13 21:52:58 +01:00
Luke Bennett
3649eb2c95
docs: fix param syntax and improve body desc 2021-06-13 21:51:53 +01:00
Luke Bennett
d3b2c90dc1
docs: remove WrongAdminPassword error response 2021-06-13 21:24:48 +01:00
EntireTwix
9b9d5cf430 made Contains return -1 instead of 0 in false case 2021-06-12 22:34:19 -07:00
EntireTwix
56bde9b341 updated 2021-06-12 21:37:19 -07:00
EntireTwix
50d4801074 updated paths 2021-06-12 21:30:13 -07:00
EntireTwix
c9fedf3228 added \"BankF\" to paths 2021-06-12 21:27:09 -07:00
EntireTwix
47accc762b changed API list order 2021-06-12 21:18:37 -07:00
EntireTwix
c9c9bee5c6 update APIs list 2021-06-12 21:08:31 -07:00
EntireTwix
3279835696 🐎 contains check for SendFunds before unique grabbed 2021-06-12 20:56:04 -07:00
EntireTwix
8f47c12450 ping function 2021-06-12 20:53:00 -07:00
EntireTwix
3e857f455e removed AdminWrongPassword error 2021-06-12 20:50:46 -07:00
EntireTwix
7711fe29d9 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-12 20:39:29 -07:00
EntireTwix
c7695dd6db made responses more inuitive for vpass and admin/vpass & fixed send funds bug 2021-06-12 20:39:07 -07:00
William Katz
cc6b9df34d
Update APIs.md 2021-06-12 11:06:56 -07:00
William Katz
87c3ee55b9
Update services.md 2021-06-12 11:06:02 -07:00
William Katz
16d9bba33e
Create APIs.md 2021-06-12 11:04:46 -07:00
William Katz
b62e05a312
Update services.md 2021-06-12 11:04:31 -07:00
William Katz
c73c3f36e7
Updated doggo's contribs 2021-06-12 11:02:01 -07:00
William Katz
18c051f8ac
Updated link of logs_consts 2021-06-12 01:14:19 -07:00
William Katz
c32a99a511
Removed comment 2021-06-12 00:48:02 -07:00
William Katz
cddbc61ea0
Update README.md 2021-06-10 22:33:36 -07:00
EntireTwix
5e8541c2a6 added credits to React for logo 2021-06-10 22:24:40 -07:00
EntireTwix
272a2bca67 updated docs with changes 2021-06-10 22:08:23 -07:00
EntireTwix
eed41a1de1 🐛 fixed unintuitive design of AddUser having password in body 2021-06-10 21:30:30 -07:00
EntireTwix
6d9d7cff71 pipped Password output rather then making a new variable 2021-06-10 20:20:10 -07:00
EntireTwix
9bcc9b13b6 made string_view to work with PASS_HEADER 2021-06-10 20:19:31 -07:00
EntireTwix
a9b629ee72 changed order of conditionals out of preference 2021-06-10 18:20:58 -07:00
EntireTwix
fa9d6e4aa4 🐎 reverting branchless code 2021-06-10 17:50:33 -07:00
EntireTwix
986829d798 🐛 fixed DelUser & AdminDelUser 2021-06-10 16:17:40 -07:00
EntireTwix
a34f3dc640 corrected error with AddUsers A state 2021-06-10 15:52:32 -07:00
EntireTwix
8c46ec3f6f updated docs for A requirement of AddUser 2021-06-10 15:49:36 -07:00
EntireTwix
b5596db9d3 reverted xxhash change 2021-06-10 14:16:44 -07:00
EntireTwix
503462508f reverted xxhash changes 2021-06-10 14:11:51 -07:00
William Katz
a025954b74
Delete help.html 2021-06-10 13:20:18 -07:00
EntireTwix
cc23bc8142 🐎 made xxhash dynamically linked 2021-06-10 13:14:12 -07:00
William Katz
8228a53d01
Merge pull request #15 from EntireTwix/Split
Split .hpp into .h and .cpp
2021-06-10 12:25:25 -07:00
William Katz
0c1f16455b
Merge branch 'main' into Split 2021-06-10 12:23:56 -07:00
EntireTwix
39b82f1ebf added link to help.md 2021-06-10 12:22:24 -07:00
EntireTwix
7dd215292f password for add user moved to header 2021-06-10 12:17:50 -07:00
William Katz
da2f18e2ef
Merge pull request #14 from EntireTwix/EndpointsFixed
Endpoints fixed
2021-06-10 12:15:25 -07:00
William Katz
6a2d2a27ab
Merge branch 'main' into EndpointsFixed 2021-06-10 12:15:16 -07:00
EntireTwix
c40c63252c somehow admin vpass was != 2021-06-10 12:00:47 -07:00
EntireTwix
0b39b2bc9e updated docs 2021-06-10 12:00:23 -07:00
EntireTwix
a219842b5a fixed miss labeling of getbal 2021-06-10 01:59:24 -07:00
EntireTwix
84f934f39d Split .hpp into .h and .cpp 2021-06-10 01:57:18 -07:00
EntireTwix
e32dbbae03 fixed/improved build instructions 2021-06-10 00:32:35 -07:00
EntireTwix
e7b41d36ff fixed/improved build instructions 2021-06-10 00:31:29 -07:00
William Katz
c7139953f6
Update README.md 2021-06-10 00:29:51 -07:00
EntireTwix
b1e8021821 fixed header for now renamed endpoint.h 2021-06-10 00:02:29 -07:00
EntireTwix
437c8b5f20 updated logs and fixed renamed header 2021-06-10 00:02:02 -07:00
EntireTwix
44949d2012 updated connected services 2021-06-09 23:58:19 -07:00
EntireTwix
169a13be2e new docs! 2021-06-09 23:50:15 -07:00
EntireTwix
179deb85cc re-ordered maps 2021-06-09 23:49:07 -07:00
EntireTwix
a59e8ae245 seperated README connected services into another file 2021-06-09 23:48:26 -07:00
EntireTwix
23e13060e5 new docs! 2021-06-09 23:47:46 -07:00
EntireTwix
c0002d1e7b seperated Connected Services into another file 2021-06-09 23:47:21 -07:00
EntireTwix
01bf8bea9a made methods GET 2021-06-09 22:00:50 -07:00
EntireTwix
c0439ed6a8 renamed to error responses 2021-06-09 21:20:58 -07:00
EntireTwix
ba21d5b6aa finished password header 2021-06-09 21:07:06 -07:00
EntireTwix
3b6cf887c8 🐛 saving bug foundg 2021-06-09 20:47:42 -07:00
EntireTwix
803aeb11c3 implementing password in header 2021-06-09 20:44:44 -07:00
EntireTwix
78ba30ccc3 Merge branch 'EndpointsFixed' of https://github.com/EntireTwix/CCash into EndpointsFixed 2021-06-09 19:37:50 -07:00
EntireTwix
37dbe3a3c6 made system indepdent 2021-06-09 19:36:39 -07:00
EntireTwix
7646d4861e further path changes 2021-06-09 17:33:51 -07:00
EntireTwix
6bc3a38aa2 🐛 load/save error caught 2021-06-09 16:20:21 -07:00
William Katz
729a3748c0
Create users.json 2021-06-09 16:14:31 -07:00
William Katz
3958369382
Create config.json 2021-06-09 16:13:49 -07:00
EntireTwix
86ab9a0e8e making error returns uniform 2021-06-09 16:12:33 -07:00
William Katz
f08313723b
Forgot about ender modems
Although an in-game solution wouldn't work across dimensions, across servers, or from the web
2021-06-09 03:59:04 -07:00
William Katz
8df5025e9f
Update README.md 2021-06-09 03:24:06 -07:00
William Katz
51bbc07bf7
Update README.md 2021-06-09 03:19:42 -07:00
William Katz
e220f26c1b
Update README.md 2021-06-09 03:15:19 -07:00
William Katz
d9075418a5
Update README.md 2021-06-08 18:14:14 -07:00
EntireTwix
b6b1c0b78e Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-07 11:14:16 -07:00
EntireTwix
0b7722e79c 🐛 remove \" -> " 2021-06-07 11:13:27 -07:00
William Katz
5d88dde6c4
Simplified initial static asserts
Changed initial check to all static assertions
2021-06-07 08:23:36 -07:00
doggo
552c2deca8 Changed initial check to all static assertions 2021-06-07 09:03:04 -05:00
William Katz
7afa380d67
Update README.md 2021-06-07 02:17:06 -07:00
William Katz
983d11aace
Update README.md 2021-06-07 00:18:45 -07:00
William Katz
d4d34d11ff
Update README.md 2021-06-07 00:18:04 -07:00
William Katz
3ba275d8e4
Update README.md 2021-06-06 23:56:18 -07:00
William Katz
80ef1d54a7
Made contribs more precise 2021-06-06 23:50:59 -07:00
William Katz
5c0fafa951
Update README.md 2021-06-06 20:49:48 -07:00
William Katz
8615c7e04e
Update README.md 2021-06-06 18:27:37 -07:00
EntireTwix
1e7203db9b added FAQ and Contribs 2021-06-06 17:31:45 -07:00
EntireTwix
037bb2ea4d Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-06 17:31:14 -07:00
William Katz
3a2f04ab3b
🐛 when pre_log_size == 0, illegal instruction would be generated 2021-06-06 17:30:45 -07:00
EntireTwix
7678d5d742 Docs HTML 2021-06-06 17:02:04 -07:00
William Katz
11647eb827
the infinitely accidentately commited 2021-06-06 16:57:28 -07:00
William Katz
a4ffee5992
removed var 2021-06-06 16:54:49 -07:00
William Katz
0947ad9b93
🐛 bugged for loop 2021-06-06 16:53:28 -07:00
William Katz
f198913ced
User construct/Add trans changes
once again this has many errors but ill merge and fix
2021-06-06 16:52:36 -07:00
doggo
a6c0595f64 Branchless loop init 2021-06-05 22:15:01 -05:00
doggo
84f835e8b8 User log constructor change
Now shifts to the end, is in order but takes only the lotest logs that it is able to.
2021-06-05 21:25:27 -05:00
doggo
6a79ca9c39 request 2021-06-04 21:51:06 -05:00
doggo
a652fded48 Changed logging, added assertations in main, changed user constructor to enforce logging struct reqs 2021-06-04 00:27:47 -05:00
EntireTwix
4455ddf308 fixed direction of getlogsg 2021-06-03 20:23:47 -07:00
EntireTwix
d5551aa74a fixed direction of getlogsg 2021-06-03 20:21:25 -07:00
EntireTwix
acfbb738bb reverted getlog direction 2021-06-03 20:18:07 -07:00
EntireTwix
2083e57d13 fixed 2021-06-03 18:41:13 -07:00
EntireTwix
2e05197791 fixed build issues 2021-06-03 18:39:18 -07:00
EntireTwix
0dae1c3a74 divisible static_assert only if max_log != 0 2021-06-03 18:35:09 -07:00
EntireTwix
819a77a299 divisible static_assert only if max_log != 0 2021-06-03 18:30:40 -07:00
EntireTwix
48c4d73cbc "<" to "<=" 2021-06-03 18:27:46 -07:00
William Katz
5095ad0adb
legacy print 2021-06-03 18:24:23 -07:00
William Katz
e6988b8abc
fixed logic 2021-06-03 18:18:13 -07:00
William Katz
c6c08832e7
reverted doggos changes till fixed 2021-06-03 18:17:43 -07:00
William Katz
5e4113bf8f
reversed endpoint to match new internal structure 2021-06-03 18:16:56 -07:00
William Katz
fa95322032
Made allocation/adding of logs more effecient
Logging update, adding transactions optimized
2021-06-03 18:08:33 -07:00
doggo
ae8ef4ae4e Added a static assertation 2021-06-03 19:21:26 -05:00
doggo
69121557a9 User constructor now enforces logging rule 2021-06-03 19:11:32 -05:00
doggo
ab11101611 Idiot changed the variable name 2021-06-03 17:36:44 -05:00
EntireTwix
9df8a6a52f 🐛 fixed new push back! 2021-06-03 15:02:47 -07:00
EntireTwix
f31c95eeea temp 2021-06-03 15:00:58 -07:00
EntireTwix
211d27c24c temp 2021-06-03 14:59:52 -07:00
doggo
af51335aa7 Code comments for logs 2021-06-03 16:50:13 -05:00
doggo
a2287a4d36 Logging update, adding transactions optimized 2021-06-03 16:40:08 -05:00
EntireTwix
9e056a640a 🐛 for loop in wrong direction when full 2021-06-03 14:19:15 -07:00
William Katz
0f41fe8283
accidentatly pushed config 2021-06-03 14:13:56 -07:00
EntireTwix
54f604402c pre alloc amount must be less then max amount 2021-06-03 14:10:09 -07:00
EntireTwix
00ec8397d6 🐛 forgot conditional for if log is has reached max size 2021-06-03 14:09:29 -07:00
William Katz
d81dd5b74b
Merge pull request #8 from EntireTwix/LogsRefractored
 major simplification via reserve() and capacity()
2021-06-03 13:52:09 -07:00
EntireTwix
d4179ed063 major simplification via reserve() and capacity() 2021-06-03 13:49:35 -07:00
EntireTwix
a78b4e5b1d 🐎 made getlogs endpoint cache result when disabled 2021-06-03 12:47:50 -07:00
EntireTwix
3609291e31 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-03 12:42:43 -07:00
William Katz
d56a781a29
accidental commit 2021-06-03 12:40:32 -07:00
EntireTwix
e14ccc17b1 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-03 12:40:06 -07:00
EntireTwix
9101a42b5d slight change 2021-06-03 02:27:35 -07:00
EntireTwix
8d5a0aeb52 slight change 2021-06-03 02:23:17 -07:00
EntireTwix
899851bec3 Simplified and Commented log end->size 2021-06-03 02:19:05 -07:00
EntireTwix
a1988d3bd5 🐛 further bug fixes 2021-06-03 01:54:58 -07:00
EntireTwix
7cef01e650 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-03 01:18:19 -07:00
EntireTwix
aa7a389de0 🐛 degrading logs bug 2021-06-03 01:17:30 -07:00
William Katz
410a6e2703
Update README.md 2021-06-01 20:28:55 -07:00
EntireTwix
9490219747 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-06-01 16:53:27 -07:00
EntireTwix
bf1a904c84 :bug 2021-06-01 16:53:22 -07:00
William Katz
59da9533f7
Create users.json 2021-06-01 16:38:49 -07:00
William Katz
44848ae75b
Delete users.json 2021-06-01 16:36:42 -07:00
EntireTwix
6927061705 default users.json location 2021-06-01 16:30:29 -07:00
William Katz
e53c54637d
Create users.json 2021-06-01 16:29:45 -07:00
EntireTwix
596ae46286 further safegaurds 2021-06-01 16:17:40 -07:00
EntireTwix
cc3aa0882a 🐛 finally fixed big "end" bug 2021-05-29 21:26:11 -07:00
EntireTwix
a799a606ff Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-05-29 20:30:38 -07:00
EntireTwix
742396c32e Serialize dont log 0 amount 2021-05-29 20:28:39 -07:00
William Katz
90bbe86d3c
Update README.md 2021-05-29 20:16:20 -07:00
EntireTwix
c833f66d9f 🐛 seg fault bug fixed 2021-05-29 20:11:02 -07:00
William Katz
7972f9857d
Update README.md 2021-05-28 16:50:01 -07:00
William Katz
099564523b
Update README.md 2021-05-28 16:30:55 -07:00
EntireTwix
56aa6f31f0 Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-05-28 16:20:27 -07:00
EntireTwix
aa91026012 🐎 improved saving for when logs are disabled 2021-05-28 16:20:21 -07:00
William Katz
48a7c34f6f
typo 2021-05-28 02:47:17 -07:00
William Katz
662685a0ac
Update user.hpp 2021-05-28 02:41:13 -07:00
William Katz
dc11416d9a
New time constructor 2021-05-28 02:39:57 -07:00
EntireTwix
239573e246 🐎 improved getlogs endpoint when max log size is 0 2021-05-28 02:25:48 -07:00
EntireTwix
a45dca028c 🐛 fixed logs finally 2021-05-28 02:23:01 -07:00
EntireTwix
efec7d0da9 🐛 fixed last commit 2021-05-28 01:58:56 -07:00
EntireTwix
4a0b7cafa6 🐛 infinite allocate bug 2021-05-28 01:56:16 -07:00
William Katz
98aac38958
I keep doing commit -am oops
I swear Im not padding commits lmao
2021-05-21 16:19:25 -07:00
EntireTwix
c95753550c 🐛 fixed a 0 amount bug on logs 2021-05-21 16:17:49 -07:00
EntireTwix
630ea79b17 legacy logging 2021-05-20 22:10:11 -07:00
EntireTwix
3b735d10ae 🐛 config changed on accident 2021-05-20 22:04:12 -07:00
EntireTwix
b808351621 🐛 Log saving fixed 2021-05-20 22:03:30 -07:00
EntireTwix
0d7b7b5df2 🐛 saving of logs bug fixed 2021-05-20 22:00:52 -07:00
William Katz
5a6ac776bd
🐛 if load data was larger then max size, incorrect resize would occur 2021-05-20 21:29:46 -07:00
EntireTwix
59417ccebf 🐛 Log Size reduction will load correctly now 2021-05-19 14:27:29 -07:00
EntireTwix
517f6dfcbe 🐛 2021-05-19 14:24:43 -07:00
EntireTwix
0d4f49213e 🐛 last commit changes 2021-05-19 14:23:41 -07:00
EntireTwix
50b27549fa Merge branch 'main' of https://github.com/EntireTwix/CCash 2021-05-19 14:20:59 -07:00
EntireTwix
dc74da6072 🐎 Max size 0 optimizations 2021-05-19 14:18:01 -07:00
82 changed files with 45812 additions and 1260 deletions

7
.dockerignore Normal file
View file

@ -0,0 +1,7 @@
/build
/help.md
/services.md
/APIs.md
/README.md
/benchmarking.cpp
/docs

15
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,15 @@
---
name: Bug report
about: an errors scope must be of CCash and not one of its connected services or
API, if so the issue should be submitted on those repos
title: "[BUG]"
labels: bug
assignees: ''
---
**Description**
* A description of the bug's effects.
**Reproducing Instructions**
* Please attempt to find a way to reliably reproduce the bug, this will speed up fixing it. (optional)

View file

@ -0,0 +1,17 @@
---
name: Feature request
about: suggestions for how to improve CCash
title: "[IDEA]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Usage**
How this would ideally be used / benefit

41
.github/workflows/build.yaml vendored Normal file
View file

@ -0,0 +1,41 @@
name: Build
on:
push:
branches:
- main
jobs:
release:
name: Push Docker image to GitHub Packages
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Checkout the repo
uses: actions/checkout@v2
- name: Login to GitHub Docker Registry
uses: docker/login-action@v1
with:
registry: docker.pkg.github.com
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Format repository
run: |
echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
- name: Build container image
uses: docker/build-push-action@v2
with:
push: true
tags: |
docker.pkg.github.com/${{ env.IMAGE_REPOSITORY }}/ccash:${{ github.sha }}
docker.pkg.github.com/${{ env.IMAGE_REPOSITORY }}/ccash:latest
trigger-deploy:
needs: release
runs-on: ubuntu-latest
steps:
- run: |
curl -X POST \
-H 'Accept: application/vnd.github.v3+json' \
-H 'Authorization: Bearer ${{ secrets.CCASH_DEPLOY_TOKEN }}' \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/deploy.yaml/dispatches \
-d '{"ref":"main"}'

4
.gitignore vendored
View file

@ -1,3 +1,5 @@
.vscode
build
config.json
ccash_config.hpp
deployment/.yamllint
config

3
.gitmodules vendored
View file

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

View file

@ -6,17 +6,98 @@ 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)
add_executable(${PROJECT_NAME} main.cpp include/xxhash.c)
find_package(Threads REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_sources(${PROJECT_NAME} PRIVATE
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 "\"../config/users.dat\"")
endif()
if(DEFINED DROGON_CONFIG_LOC)
set(DROGON_CONFIG "\"${DROGON_CONFIG_LOC}\"")
else()
set(DROGON_CONFIG "\"../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 ADD_USER_OPEN)
set(ADD_USER_OPEN_VAL ${ADD_USER_OPEN})
else()
set(ADD_USER_OPEN_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()
if(DEFINED USE_DEPRECATED_ENDPOINTS)
set(USE_DEPRECATED_ENDPOINTS_VAL ${USE_DEPRECATED_ENDPOINTS})
else()
set(USE_DEPRECATED_ENDPOINTS_VAL true)
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)

21
Dockerfile Normal file
View file

@ -0,0 +1,21 @@
FROM alpine:latest
WORKDIR /
RUN apk update && apk add bash git cmake g++ make protobuf jsoncpp-dev openssl libressl-dev zlib-dev util-linux-dev libtool autoconf automake python3
RUN git clone --recurse-submodules https://github.com/EntireTwix/CCash.git
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.dat" ..
RUN make -j$(nproc)
ARG ADMIN_A=admin
ARG SAVE_FREQ=2
WORKDIR /
RUN sed -i 's/\r$//' /CCash/config/ssl.sh && \
chmod +x /CCash/config/ssl.sh
RUN /CCash/build/bank
CMD /CCash/config/ssl.sh && /CCash/build/bank ${ADMIN_A} ${SAVE_FREQ}

873
LICENSE
View file

@ -1,622 +1,281 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Version 2, June 1991
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
13. Use with the GNU Affero General Public License.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
14. Revised Versions of this License.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
NO WARRANTY
15. Disclaimer of Warranty.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
@ -628,15 +287,15 @@ free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@ -644,31 +303,37 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

104
README.md
View file

@ -1,93 +1,17 @@
# CCash
![image](https://user-images.githubusercontent.com/31377881/139971016-9ca428d1-1a17-4c87-85e3-9b7ead0780f5.png)
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:
* [problem/solution](docs/idea.md)
* connected services
* how to create
* [explanation](docs/connected_services/how_to/explanation.md)
* [API implementations](docs/connected_services/how_to/APIs.md)
* [the API](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)
- 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
```
sudo apt install libjsoncpp-dev
sudo apt install uuid-dev
sudo apt install openssl
sudo apt install libssl-dev
sudo apt install zlib1g-dev
```
building the project
```
git clone --recurse-submodule https://github.com/EntireTwix/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
Go to `{ip}/BankF/help` to see the bank's methods (also found in releases as help.html). Using the Bank's API allows (you/others) to (make/use) connected services that utilize the bank, a couple ideas are
### Implemented:
- [Web Frontend](https://github.com/Expand-sys/ccashfrontend)
![image](https://user-images.githubusercontent.com/31377881/116965729-4ab44500-ac63-11eb-9f11-dc04be6b3d63.png)
- [CC Frontend](https://github.com/Reactified/rpm/blob/main/packages/ccash-wallet/wallet.lua)
![image](https://user-images.githubusercontent.com/31377881/116967157-8b618d80-ac66-11eb-8f2e-4a6297ef0b16.png)
- [CC API](https://github.com/Reactified/rpm/blob/main/packages/ccash-api/api.lua)
### In-Dev:
- [a Market](https://github.com/STBoyden/market-api-2.0)
### Ideas:
- Gambling
- Shipping
- High-level bank operations such as loans
- Some trust based system for transactions similiar to Paypal
`**WARNING** : abruptly killing the program will result in data loss, use Close() method to close safely`
## Features
### Performance
- **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://github.com/the-benchmarker/web-frameworks)
- **Lightweight**, anecodotally I experienced <1% CPU usage on average, 7% at peak (1000 requests in parallel of 8), 0.0% idle
### Safety
- **Tamper Proof** relative to an in-game implementation
- **Auto-Saving** and Saves on close
- **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**. In contrast to an in-game modded implementation that would be range limited.
- **Logging** of all transactions, configurable in [log_consts.hpp](include/log_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)
* [Versions](docs/versioning.md)

105
benchmarking.cpp Normal file
View file

@ -0,0 +1,105 @@
#include <iostream>
#include <chrono>
#include <thread>
#include <sys/types.h>
#include <unistd.h>
#include <random>
#include "xxhash_str.h"
#include "bank.h"
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
using namespace std::chrono;
#include <ctime>
#include <ratio>
#include <chrono>
#define time_func_a(f, a, x) \
{ \
using namespace std::chrono; \
uint32_t timer = 0; \
for (int i = 0; i < x; ++i) \
{ \
auto t1 = high_resolution_clock::now().time_since_epoch(); \
f; \
auto t2 = high_resolution_clock::now().time_since_epoch(); \
a; \
timer += std::chrono::duration_cast<std::chrono::nanoseconds>((t2 - t1)).count(); \
} \
std::cout << timer / x << '\n'; \
}
#define time_func(f, x) \
{ \
using namespace std::chrono; \
uint32_t timer = 0; \
for (int i = 0; i < x; ++i) \
{ \
auto t1 = high_resolution_clock::now().time_since_epoch(); \
f; \
auto t2 = high_resolution_clock::now().time_since_epoch(); \
timer += std::chrono::duration_cast<std::chrono::nanoseconds>((t2 - t1)).count(); \
} \
std::cout << timer / x << '\n'; \
}
#define Op_a(v, name, x, a) \
{ \
std::cout << name; \
time_func_a(v, a, x); \
}
#define Op(v, name, x) \
{ \
std::cout << name; \
time_func(v, x); \
}
int main(int argc, char **argv)
{
for (size_t i = 100; i < 10100; ++i)
{
Bank::AddUser(std::to_string(i), 0, "root");
}
std::cout << "added " << Bank::NumOfUsers() << " users\n";
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::GetBal("twix"), "get bal: ", 1000000);
Op(Bank::VerifyPassword("twix", "root"), "verify pass: ", 1000000);
Op(Bank::ChangePassword("twix", "root"), "change pass: ", 1000000);
#if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
Op(Bank::GetLogs("twix"), "get logs init: ", 1);
Op(Bank::GetLogs("twix"), "get logs cached: ", 1000000);
#endif
Op(Bank::GetLogsV2("twix"), "get logs init (v2): ", 1);
Op(Bank::GetLogsV2("twix"), "get logs cached (v2): ", 1000000);
Op(Bank::GetLogsRange("twix", 0, 100), "get logs range: ", 1000000);
#endif
Op(Bank::PruneUsers(0, 0), "prune users: ", 1);
Op(Bank::Save(), "saving: ", 1);
return 0;
}

35
ccash_config.hpp.in Normal file
View file

@ -0,0 +1,35 @@
#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@
#define MULTI_THREADED @MULTI_THREADED_VAL@
#define ADD_USER_OPEN @ADD_USER_OPEN_VAL@
#define USE_DEPRECATED_ENDPOINTS @USE_DEPRECATED_ENDPOINTS_VAL@

View file

@ -1,16 +0,0 @@
{
"listeners": [
{
"address": "0.0.0.0",
"port": 80,
"https": false
},
{
"address": "0.0.0.0",
"port": 443,
"https": true,
"cert": "",
"key": ""
}
]
}

16
config/config.json Normal file
View 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
View 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

BIN
config/users.dat Normal file

Binary file not shown.

20
docs/FAQ.md Normal file
View file

@ -0,0 +1,20 @@
[PREVIOUS PAGE](building.md)
### How do I setup a CCash instance
You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package.
### Why is my username invalid
Usernames are restricted by minecraft's requirements
* letters
* numbers
* _
* length must be atleast 3 and at most 16 characters.
### Is this crypto like krist?
CCash isn't a crypto, simply a ledger keeping track of who owns what.
### Why isnt this on a database?
Because this usecase requires none of the features a database would offer.
### People are making too many accounts maliciously to fill up space on my server!
Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
### My instance is taking up too much storage or RAM
Reduce log size and/or use the prune users endpoint to remove dead accounts.
### Why not use an economy mod
Speed of operations, CCash being external to MC (and so compatible with any version/configuration), and the API are the main advantages to an economy mod.

159
docs/building.md Normal file
View file

@ -0,0 +1,159 @@
# 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, such that each time save frequency is met, changes having been made 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 139 bytes in memory and 43 bytes in disk at default settings on the current version, so 7543 logs per MB of RAM. Setting to 0 will disable logs
* with no users memory usage is ~8.47 MB
* saving frequency being set to 0 will disable frequency saving and only save on close
* make backups of your save files!
## Docker & Ansible
If you want to use the docker package, deploy information can be found [here](deploy.md)
## Drogon Depedencies
### Linux
#### Debian
```
sudo apt install libjsoncpp-dev uuid-dev openssl libssl-dev zlib1g-dev make cmake
```
#### 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
```
#### Other
anything that can download the appropriate dependencies
```
make & cmake
jsoncpp
libuuid
openssl
zlib
```
### MacOS
```
brew install jsoncpp ossp-uuid openssl zlib
```
## 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
```
### CMake Variables
there are multiple flags responsible configuring CCash:
| name | default | description | pros | cons |
| :----------------------- | :------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
| USER_SAVE_LOC | "config/users.dat" | where the users are saved | `N/A` | `N/A` |
| DROGON_CONFIG_LOC | "config/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 |
| ADD_USER_OPEN | `true` | anybody can make a new account, if set to false only admins can add accounts via `AdminAddUser()` | `N/A` | spamming new users |
| USE_DEPRECATED_ENDPOINTS | `true` | some endpoints have newer versions making them obsolete but old programs might still call these endpoints so they are simply marked deprecated. | supports old programs | old endpoints can be ineffecient |
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>
sudo ./bank
```
the last command generates a blank save file in your defined location.
## 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
}
]
}
```
## Usage
You can now run the program from the build location. For example
```
sudo ./bank admin 5
```
in this example CCash will be launched with the admin account named `"admin"`, and a saving frequency of every `5` minutes; without daemon being given its default is `false`.
Another example
```
sudo ./bank Kevin 0 true
```
in this example CCash will be launched with the admin account named `"Kevin"`, and a saving frequency of `0` meaning the server will only save when closed; daemon is set to `true` and so will be launched in the background.

View file

@ -0,0 +1,32 @@
[PREVIOUS PAGE](how_to/endpoints.md) | [NEXT PAGE](../features/user_side.md)
## Key
| description | symbol |
| :-----------------------: | :----------------- |
| supported | :heavy_check_mark: |
| uses deprecated endpoints | ⚠ |
| uses defunt endpoints | :no_entry: |
| in development | :hammer: |
## General
| author | name | support | image |
| :-------------------------------------- | ----------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121337724-afe9fe80-c8d1-11eb-8851-23ec5e74cd26.png) | |
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | |
## Minecraft
| author | name | support | image |
| :------------------------------------------ | ---------------------------------------------------------------------------------------- | :----------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/120050327-de163700-bfd1-11eb-9d5a-f75c003e867c.png) |
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ | ![image](https://user-images.githubusercontent.com/31377881/121338034-fb041180-c8d1-11eb-8640-b18c141eb980.png) |
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121277361-4d6b1100-c885-11eb-87c8-cfebcf58da4f.png) |
| [Reactified](https://github.com/Reactified) | [Chunk Loader Shop](https://github.com/Reactified/rpm/tree/main/packages/forceload-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/209894520-f7183f45-bbac-40f3-9f95-043bda3c0097.png) ![image](https://user-images.githubusercontent.com/31377881/209894553-16ef7e04-52e7-4198-8a39-9ad2ada6eaf7.png) |
| [STBoyden](https://github.com/STBoyden) | [Commodities Exchange](https://github.com/STBoyden/ccash-market) | :hammer: | |
## Desired
| idea | description |
| :-----------: | :------------------------------------------------------------- |
| Gambling | physical or digital casino. |
| Shipping | the infastructure to quickly send items across long distances. |
| Mod or Plugin | a server-side mod |

View file

@ -0,0 +1,41 @@
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
CCash is backwards compatible, so even if a language API does not support the newester version it can still call the old endpoints. Only when the major version increments are deprecated features made defunct (e.g `v1.0.0` -> `v2.0.0`), check the [endpoint docs](endpoints.md) to avoid using deprecated endpoints. For more information about versioning check out [versioning docs](../../versioning.md).
| author | language | | newest CCash supported version |
| :-------------------------------------------------------- | :--------: | -------------------------------------------------------------------- | :----------------------------: |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | `v2.5.1` |
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://github.com/STBoyden/ccash-rs) | `v2.5.1` |
| [Doggo](https://github.com/ArcNyxx) | Python | [CCashPythonClient](https://github.com/ArcNyxx/ccash_python_client) | `v2.5.1` |
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | TypeScript | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | `v1.3.0` |
here is a demo program for the lua API by SpaceCat
```lua
local ccash = require("ccash.api")
ccash.meta.set_server_address("https://ccashinstance.net/")
local cred_name = "my_account"
local cred_pass = "my_pass"
math.randomseed(os.time())
local temp_name = tostring(math.random(100, 2147483647))
print("temp account "..temp_name)
print("enter target name ")
local target_name = io.read()
print("enter target amount ")
local target_amount = tonumber(io.read())
print(ccash.register(temp_name, "root123"))
print(ccash.send_funds(cred_name, cred_pass, temp_name, target_amount))
print(ccash.send_funds(temp_name, "root123", target_name, target_amount))
print(ccash.delete_self(temp_name, "root123"))
```
this particular program obfuscates transactions so that the person receiving it has no way of knowing who it came from
```
my_account -> temp_account -> target_account
+100 +100
```
then temp_account is deleted

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,98 @@
# 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
⚠ - Deprecated endpoint
:no_entry: - Defunct endpoint
## all error responses have JSON string along with them to describe
### Usage endpoints
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: |
| GetBal | `v2.3.0` | 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: | :x: | :x: | :x: |
| GetLogs | `v2.3.0` | retrieves the logs of a given user, length varies by server configuration (oldest to newest transactions) | `N/A` | ⚠ api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| GetLogsV2 | `v2.6.1` | retrieves the logs of a given user, length varies by server configuration (newest to oldest transactions) | `N/A` | api/v2/user/log | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| GetLogsRange | `v2.6.1` | retrieves the logs of a given user, where `{start}` is the 0-indexed first log and `{length}` is the number of logs after that index. | `N/A` | api/v1/user/log_range | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| SendFunds | `v2.3.0` | 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: | :x: | :heavy_check_mark: |
| ChangePassword | `v2.3.0` | 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: | :x: | :heavy_check_mark: |
| VerifyPassword | `v2.3.0` | 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: | :x: | :x: | :heavy_check_mark: |
### Usage enpoint errors
| name | 400 | 401 | 404 | 406 |
| :------------- | :----------------: | :----------------: | :----------------: | :----------------: |
| GetBal | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
### Meta Usage endpoints
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------------ | :---------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| AdminGetLogs | `v2.6.1` | retreives the logs of a given user `{name}`, length varies by server configuration | `N/A` | api/v1/admin/user/log?name={name} | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| AdminChangePassword | `v2.3.0` | 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: | :x: |
| AdminVerifyAccount | `v2.3.0` | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| SetBal | `v2.3.0` | 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: | :x: |
| ImpactBal | `v2.3.0` | modifies the user `"name"`'s balance by `"amount"` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### Meta Usage endpoint errors
| name | 400 | 401 | 404 | 406 |
| :------------------ | :----------------: | :----------------: | :----------------: | :----------------: |
| AdminGetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminVerifyAccount | :x: | :heavy_check_mark: | :x: | :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: |
### Sytem Usage endpoints
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------ | :---------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: |
| Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| Contains | `v2.3.0` | checks wether a given user `{name}` exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :x: |
| PruneUsers | `v2.3.0` | deletes users with most recent transactions older then `"time"` (if logs are enabled) and have less money then `"amount"` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ApiProperties | `v2.5.1` | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"max_log":uint64, "add_user_open":boolean, "return_on_del":string} | :heavy_check_mark: | :x: | :x: | :x: |
### System Usage endpoin errors
| name | 401 | 404 | 406 |
| :------------ | :----------------: | :----------------: | :----------------: |
| Help | :x: | :x: | :x: |
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ApiProperties | :x: | :x: | :x: |
### Username Requirements
Valid
* letters
* numbers
* _
* Length must be atleast 3 and at most 16 characters.
### User Management endpoints
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------- | :---------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | `v2.3.0` | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
| AdminAddUser | `v2.3.0` | 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: | :x: |
| DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| AdminDelUser | `v2.3.0` | 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: | :x: |
### User Management endpoint errors
| name | 400 | 401 | 404 | 406 | 409 |
| :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| DelSelf | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |

View 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 which utilize the ledger. Below is a visual represenation of connected services:
![image](connected_a.png)
Ideally as the ecosystem develops, connected services become inner-connected:
![image](connected_b.png)
The aim of any of these services is to provide functionality which relies on the ground truth of ownership of currency. This information is centrally secured in CCash.
To browse the currently available connected 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). What they do is provide a simplified in-langauge way to interface with the CCash instance.
![image](connected_c.png)
If an API does not exist for your language, it is simple to make one. 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).

10
docs/contributors.md Normal file
View file

@ -0,0 +1,10 @@
# Contributors
| name | work |
| :------------------------------------------- | ---------------------------------- |
| [Luke](https://github.com/LukeeeeBennett) | Github Actions, and JS API |
| [React](https://github.com/Reactified) | Logo, CC Wallet/Shop/ATM |
| [Doggo](https://github.com/FearlessDoggo21) | HTTP advice, Python API, and C CLI |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
| [Expand](https://github.com/Expand-sys) | Docker, and Ansible |
| [Sam](https://github.com/STBoyden) | Rust API |
| Caesay | Restful API advice |

47
docs/deploy.md Normal file
View file

@ -0,0 +1,47 @@
# Deploying CCash
CCash can deployed to a remote machine pretty simply.
A pre-built docker image is supplied in the repos [GitHub Packages](https://github.com/features/packages) container registry [EntireTwix/CCash](https://github.com/EntireTwix/CCash/packages/851105).
It can be run with docker like so:
```
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ghcr.io/entiretwix/ccash/ccash:latest
```
## Ansible
Additionally CCash can be deployed to any infrastructure able to run Rocky/Alma Linux 8/9 x86_64 virtual or not, we will be eventually updating it to allow it to run on other OS's but for now RHEL is what works.
As CCash is intended to be run as root, the playbook is run also as root. The playbook also builds CCash from the latest github push, so there may be bugs.
In order to use the ansible playbook, clone the playbook to any pc with the ability to access the server through SSH and with Ansible installed, edit the inventory file to contain the IP address of the target server and run the following commands:
```ansible-galaxy install -r deployment/requirements.yml
```ansible-playbook -i deployment/inventory deployment/main.yml -k```
When this is complete the server will have ccash installed to the user dir, this is customizable in the vars/default.yml file along with the admin username and save frequency.
To start CCash run:
```systemctl start ccash```
To run ccash at start up run:
```systemctl enable ccash```
## Build
Previously this used GitHub Workflows, I(Expand) dont know how to do those but its not that hard to deploy stuff manually. To run the pre configured docker image run the above command and you are off to the races it will deploy a self signed certificate and use that for deployment. As this is not a user facing deployment the certificate is self signed and thus will throw an error on chrome, though this will still work if you ignore it. For production you should deploy with a reverse proxy and a correct certificate for your domain.
To build this manually you may download the dockerfile only, it will pull the latest repository the commands for building are
```
docker build --build-arg ADMIN_A=<admin-username> --build-arg SAVE_FREQ=<in minutes> -t ccash . --no-cache
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ccash
```
if you have the know how you may edit the docker file and add CMAKE commands as listed in the build section of the CCash documentation.
## Deploy
You can deploy this docker image to be run on a remote machine in a few steps or you can deploy manually in this case we are using [Debian OS](https://www.debian.org/) running on the [Linode](https://www.linode.com/) cloud provider, but most OS and cloud providers will work, assuming the machine can run an SSH server.
Additionally, there is a dockerfile where you can build it yourself or a repository available on [dockerhub](https://hub.docker.com/r/expandsys/ccash) for you to just pull and run on any machine quickly and easily.
### Configure the machine
For docker deployment there is one supported config and that is the command listed above,
ADMIN_A = Admin account name, must be all lowercase, and the account must be created before use. To do this either use the [CCashDeploy](https://hub.docker.com/r/expandsys/ccashdeploy) docker image and use the CCashFrontend to register the account or use curl to send the raw command to the endpoint.
SAVE_FREQ = Saving frequency in minutes, pretty simple

BIN
docs/external_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,47 @@
[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/).
![image](https://raw.githubusercontent.com/greg7mdp/parallel-hashmap/master/html/img/stl_flat_both.PNG)
![image](https://raw.githubusercontent.com/greg7mdp/parallel-hashmap/master/html/img/lock_various_sizes.PNG)
## [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) |
| --------------------- | ----- | ---------------- |
| __XXH3__ (SSE2) | 64 | 31.5 GB/s |
| _RAM sequential read_ | N/A | 28.0 GB/s |
## [Base64](https://github.com/aklomp/base64)
base64 decoding is required for Basic Auth so I used this clean and fast solution which uses SIMD.
![image](https://github.com/aklomp/base64/blob/master/base64-benchmarks.png)
## [Simdjson](https://github.com/simdjson/simdjson)
simdjson was the fastest JSON parsing I could find, its used for request parsing.
![image](https://github.com/simdjson/simdjson/blob/master/doc/rome.png)
## [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.
![image](https://user-images.githubusercontent.com/31377881/125891266-570c5154-8ae2-4358-9d7b-ccd82a18b132.png)
## 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`.
## Backwards Compatible API
versioning is implemented by the endpoints path, for example `api/v1/`. Breaking changes will ideally be sparse and backwards compatability will be maintained, for example ideally API `v3` instance can still run `v1` endpoints.

View file

@ -0,0 +1,33 @@
[PREVIOUS PAGE](../connected_services/existing_services.md) | [NEXT PAGE](implementation.md)
# Features
## Performance
#### Speed
<!-- graphs -->
Capable of processing thousands of requests per second, with little slow down as user size grows to the millions.
#### Lightweight
<!-- specs -->
* Low memory usage at 8 MB baseline, and 139 bytes per new log.
* Extremely low CPU usage in the single digits of %.
* Small save files at typically a couple kb, easily shareable.
## Accessibility
#### Connected Services
as explained in earlier docs a ecosystem of connected services allows you many ways to utilize CCash.
#### APIs
for devs who wanna make more connected services, existing APIs exist in multiple lanaguages enabling faster development/maintenance.
#### External
its game indepedent meaning you dont have to be in-game to use it. With support for Docker and Ansible Playbook.
## Security
#### HTTPS
OpenSSL is used to secure the HTTP server.
#### Hashed Passwords
if the server's save file is compromised the user passwords will not be derivable.
## Other
#### Logs
each transaction is logged and the last `n` logs are stored, if set to 0 logs will be disabled.
#### Return On Delete
by default this feature is off, but when enabled deleted account's funds will be redirected to a specified account rather then "burned"
#### Configurable
as you can read in [building.md](../building.md) CCash is highly configurable.
#### Game Independent
As CCash does not require an addition to the game in the form of a mod or plugin, it can be ran on any server.

30
docs/idea.md Normal file
View file

@ -0,0 +1,30 @@
[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 usecase.
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.
* Some resources are passively reapable (e.g iron or gold), making the generation of currency a larger focus than that of creating value.
* Locality is required for transactions.
* Theft is possible; ownership is physical possession based.
CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on, CCash can proccess thousands of requests per second.
The CCash instance can be external to the game server:
![image](external_diagram.png)
Or on localhost:
![image](localhost_diagram.png)
Running it local to the game server reduces latency for connected services and CCash is very lightweight and so will be a tiny proportion of the server's total computation.
**DISCLAIMER: ComputerCraft requires you add `127.0.0.1` to its config section `allowed_domains` if you're interacting with CCash locally**
As CCash is just a means of keeping track of who has what, the economic system you use is entirely up to whomever hosts the instance.
I suggest an admin should manage the instance to lower incentive to manipulate balances.

BIN
docs/localhost_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

12
docs/versioning.md Normal file
View file

@ -0,0 +1,12 @@
# Versioning
## Endpoint Version
When changing an existing endpoint in a breaking way the version will increment in the path e.g `api/v1/user/log` -> `api/v2/user/log`. If the change is non-breaking then extra parameters will simply be added to the endpoint. If the older version is marked deprecated it will be documented in [endpoints.md](connected_services/how_to/endpoints.md)
## Release Version
Major changes (e.g `v1.0.0` -> `v2.0.0`) denote a breaking change as all previously deprecated endpoints will now be made defunct and wont be built with that release.
Minor changes (e.g `v1.0.0` -> `v1.1.0`) denote a non-breaking change that adds or changes something about CCash.
Patches (e.g `v1.0.0` -> `v1.0.1`) denote bug fixes or docs changes.

27
fbe/user_model.fbe Normal file
View file

@ -0,0 +1,27 @@
package bank_dom
struct Transaction
{
string counterparty = "";
bool receiving = false;
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;
}

199
fbe/user_model/bank_dom.cpp Normal file
View file

@ -0,0 +1,199 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom.h"
namespace bank_dom {
Transaction::Transaction()
: counterparty("")
, receiving(false)
, amount((uint32_t)0ull)
, time((uint64_t)0ull)
{}
Transaction::Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time)
: counterparty(arg_counterparty)
, receiving(arg_receiving)
, 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(counterparty, other.counterparty);
swap(receiving, other.receiving);
swap(amount, other.amount);
swap(time, other.time);
}
std::ostream& operator<<(std::ostream& stream, const Transaction& value)
{
stream << "Transaction(";
stream << "counterparty="; stream << "\"" << value.counterparty << "\"";
stream << ",receiving="; stream << (value.receiving ? "true" : "false");
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

240
fbe/user_model/bank_dom.h Normal file
View file

@ -0,0 +1,240 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.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 counterparty;
bool receiving;
uint32_t amount;
uint64_t time;
size_t fbe_type() const noexcept { return 1; }
Transaction();
Transaction(const std::string& arg_counterparty, bool arg_receiving, 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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Transaction> : ostream_formatter {};
#endif
template<>
struct std::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 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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Logs> : ostream_formatter {};
#endif
template<>
struct std::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 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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::User> : ostream_formatter {};
#endif
template<>
struct std::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 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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Global> : ostream_formatter {};
#endif
template<>
struct std::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 bank_dom {
} // namespace bank_dom

View file

@ -0,0 +1,640 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom_final_models.h"
namespace FBE {
FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
, counterparty(buffer, 0)
, receiving(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
+ counterparty.fbe_allocation_size(fbe_value.counterparty)
+ receiving.fbe_allocation_size(fbe_value.receiving)
+ 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;
counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.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;
receiving.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.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;
counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.get(fbe_value.counterparty);
fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size;
receiving.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.get(fbe_value.receiving);
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;
counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.set(fbe_value.counterparty);
fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size;
receiving.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.set(fbe_value.receiving);
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

View file

@ -0,0 +1,322 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.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> counterparty;
FinalModel<bool> receiving;
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

View file

@ -0,0 +1,932 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom_models.h"
namespace FBE {
FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
, counterparty(buffer, 4 + 4)
, receiving(buffer, counterparty.fbe_offset() + counterparty.fbe_size())
, amount(buffer, receiving.fbe_offset() + receiving.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
+ counterparty.fbe_size()
+ receiving.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()
+ counterparty.fbe_extra()
+ receiving.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 + counterparty.fbe_size()) > fbe_struct_size)
return true;
if (!counterparty.verify())
return false;
fbe_current_size += counterparty.fbe_size();
if ((fbe_current_size + receiving.fbe_size()) > fbe_struct_size)
return true;
if (!receiving.verify())
return false;
fbe_current_size += receiving.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 + counterparty.fbe_size()) <= fbe_struct_size)
counterparty.get(fbe_value.counterparty, "");
else
fbe_value.counterparty = "";
fbe_current_size += counterparty.fbe_size();
if ((fbe_current_size + receiving.fbe_size()) <= fbe_struct_size)
receiving.get(fbe_value.receiving, false);
else
fbe_value.receiving = false;
fbe_current_size += receiving.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
{
counterparty.set(fbe_value.counterparty);
receiving.set(fbe_value.receiving);
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

View file

@ -0,0 +1,398 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe
// FBE version: 1.14.1.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> counterparty;
FieldModel<bool> receiving;
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

415
fbe/user_model/fbe.cpp Normal file
View file

@ -0,0 +1,415 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "fbe.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <rpc.h>
#undef DELETE
#undef ERROR
#undef HOST_NOT_FOUND
#undef Yield
#undef min
#undef max
#undef uuid_t
#endif
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, &timestamp) != 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

667
fbe/user_model/fbe.h Normal file
View file

@ -0,0 +1,667 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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)
#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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <>
struct fmt::formatter<FBE::decimal_t> : formatter<std::string_view>
{
template <typename FormatContext>
auto format(const FBE::decimal_t& value, FormatContext& ctx) const
{
return formatter<string_view>::format((double)value, ctx);
}
};
#endif
template <>
struct std::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 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
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <>
struct fmt::formatter<FBE::uuid_t> : formatter<std::string_view>
{
template <typename FormatContext>
auto format(const FBE::uuid_t& value, FormatContext& ctx) const
{
return formatter<string_view>::format(value.string(), ctx);
}
};
#endif
template <>
struct std::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 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

View file

@ -0,0 +1,438 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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

View file

@ -0,0 +1,459 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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"

View file

@ -0,0 +1,637 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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 = TKey();
TValue value = TValue();
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 = TKey();
TValue value = TValue();
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

View file

@ -0,0 +1,516 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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

471
fbe/user_model/fbe_models.h Normal file
View file

@ -0,0 +1,471 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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"

View file

@ -0,0 +1,689 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE
// FBE version: 1.14.1.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 = TKey();
TValue value = TValue();
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 = TKey();
TValue value = TValue();
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

74
include/bank.h Normal file
View file

@ -0,0 +1,74 @@
#pragma once
#include <cassert>
#include <fstream>
#include <shared_mutex>
#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
{
#if MULTI_THREADED
static phmap::parallel_flat_hash_map<
std::string, User,
xxHashStringGen,
phmap::priv::hash_default_eq<std::string>,
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
4UL,
std::mutex>
users;
#else
static phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> users;
#endif
private:
#if CONSERVATIVE_DISK_SAVE
static ChangeFlag<false> save_flag;
#endif
// must grab as shared if the operation is gonna modify "users"'s size or can be caught in a intermediary state such as SendFunds()
// must grab as unique if the operation is gonna use user iterators
static std::shared_mutex iter_lock;
public:
static std::string admin_account;
static size_t NumOfUsers() noexcept;
static size_t NumOfLogs() noexcept;
static size_t SumBal() noexcept;
static BankResponse GetBal(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
static BankResponse GetLogs(const std::string &name) noexcept;
#endif
static BankResponse GetLogsV2(const std::string &name) noexcept;
static BankResponse GetLogsRange(const std::string &name, size_t n, size_t m) noexcept;
#endif
static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept;
static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept;
static BankResponse SetBal(const std::string &name, int64_t amount) noexcept;
static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
static bool Contains(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0
static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept;
#else
static BankResponse PruneUsers(uint32_t threshold_bal) noexcept;
#endif
static BankResponse AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept;
static BankResponse DelUser(const std::string &name) noexcept;
static void DelSelf(const std::string &name) noexcept;
static const char *Save();
static void Load();
};

View file

@ -1,234 +0,0 @@
#pragma once
#include <fstream>
#include <shared_mutex>
#include "xxhash.h"
#include "parallel-hashmap/parallel_hashmap/phmap.h"
#include "user.hpp"
class
{
private:
phmap::parallel_flat_hash_map<
std::string, User,
phmap::priv::hash_default_hash<std::string>,
phmap::priv::hash_default_eq<std::string>,
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
4UL,
std::mutex>
users;
/**
* @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;
/**
* @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;
public:
std::string admin_pass;
bool AddUser(const std::string &name, std::string &&init_pass)
{
if (name.size() > 50)
{
return false;
}
std::shared_lock<std::shared_mutex> lock{size_l};
return users.try_emplace_l(
name, [](User &) {}, std::move(init_pass));
}
bool AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass)
{
if (name.size() > 50)
{
return false;
}
bool state = (admin_pass == attempt);
if (state)
{
std::shared_lock<std::shared_mutex> lock{size_l};
state = users.try_emplace_l(
name, [](User &) {}, init_bal, std::move(init_pass));
}
return state;
}
bool DelUser(const std::string &name, const std::string &attempt)
{
std::shared_lock<std::shared_mutex> lock{size_l};
return users.erase_if(name, [&attempt](User &u) { return (XXH3_64bits(attempt.data(), attempt.size()) == u.password); });
}
bool AdminDelUser(const std::string &name, const std::string &attempt)
{
std::shared_lock<std::shared_mutex> lock{size_l};
return users.erase_if(name, [this, &attempt](const User &) { return (admin_pass == attempt); });
}
bool SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt)
{
//cant send money to self, from self or amount is 0
if (a_name == b_name || !amount)
{
return false;
}
//if A exists, A can afford it, and A's password matches
bool state = false;
{
std::shared_lock<std::shared_mutex> lock{send_funds_l}; //because SendFunds requires 3 locking operations
users.modify_if(a_name, [&state, amount, &attempt](User &a) {
if (state = (a.balance >= amount) && (a.password == XXH3_64bits(attempt.data(), attempt.size())))
{
a.balance -= amount;
}
});
if (state)
{
//if B doesnt exist
if (!users.modify_if(b_name, [amount](User &b) {
b.balance += amount;
}))
{
//attempt to refund if A exist
users.modify_if(a_name, [amount](User &a) {
a.balance += amount;
});
return false; //because had to refund transaction
}
}
}
if (state)
{
Transaction temp(a_name, b_name, amount);
Transaction temp2 = temp;
users.modify_if(a_name, [&temp](User &a) {
a.log.AddTrans(std::move(temp));
});
users.modify_if(b_name, [&temp2](User &b) {
b.log.AddTrans(std::move(temp2));
});
}
return state;
}
bool Contains(const std::string &name) const
{
return users.contains(name);
}
bool SetBal(const std::string &name, const std::string &attempt, uint32_t amount)
{
bool state = (admin_pass == attempt);
if (state)
{
users.modify_if(name, [amount](User &u) {
u.balance = amount;
});
}
return state;
}
bool AdminVerifyPass(const std::string &attempt)
{
return admin_pass == attempt;
}
int_fast64_t GetBal(const std::string &name) const
{
int_fast64_t res = -1;
users.if_contains(name, [&res](const User &u) {
res = u.balance;
});
return res;
}
int_fast8_t VerifyPassword(const std::string &name, const std::string &attempt) const
{
int_fast8_t res = -1;
users.if_contains(name, [&res, &attempt](const User &u) {
res = u.password == XXH3_64bits(attempt.data(), attempt.size());
});
return res;
}
int_fast8_t ChangePassword(const std::string &name, const std::string &attempt, std::string &&new_pass)
{
int_fast8_t res = -1;
users.modify_if(name, [&res, &attempt, &new_pass](User &u) {
res = (u.password == XXH3_64bits(attempt.data(), attempt.size()));
if (res)
{
u.password = XXH3_64bits(new_pass.data(), new_pass.size());
}
});
return res;
}
Json::Value GetLogs(const std::string &name, const std::string &attempt)
{
Json::Value res;
if (!users.if_contains(name, [&res, &attempt](const User &u) {
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
{
res = 0;
}
else
{
res = u.log.Serialize();
}
}))
{
return -1;
}
return res;
}
void Save()
{
Json::StreamWriterBuilder builder;
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
std::ofstream user_save("users.json");
Json::Value temp;
//loading info into json temp
{
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();
});
}
}
writer->write(temp, &user_save);
user_save.close();
}
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
void Load()
{
Json::CharReaderBuilder builder;
Json::Value temp;
std::ifstream user_save("users.json");
builder["collectComments"] = true;
JSONCPP_STRING errs;
if (!parseFromStream(builder, user_save, &temp, &errs))
{
user_save.close();
}
else
{
user_save.close();
for (const auto &u : temp.getMemberNames())
{
users.try_emplace(u, temp[u]["balance"].asUInt(), std::move(temp[u]["password"].asUInt64()), std::move(temp[u]["log"]));
}
}
}
} bank;

91
include/bank_api.h Normal file
View file

@ -0,0 +1,91 @@
#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>
{
public:
static void GetBal(req_args, const std::string &name);
#if USE_DEPRECATED_ENDPOINTS
static void GetLogs(req_args);
#endif
static void GetLogsV2(req_args);
static void GetLogsRange(req_args, size_t start, size_t length);
static void SendFunds(req_args);
static void ChangePassword(req_args);
static void VerifyPassword(req_args);
static void AdminGetLogs(req_args, const std::string& name);
static void AdminChangePassword(req_args);
static void AdminVerifyAccount(req_args);
static void SetBal(req_args);
static void ImpactBal(req_args);
static void Help(req_args);
static void Close(req_args);
static void Contains(req_args, const std::string &name);
static void PruneUsers(req_args);
static void ApiProperties(req_args);
static void AddUser(req_args);
static void AdminAddUser(req_args);
static void DelSelf(req_args);
static void AdminDelUser(req_args);
METHOD_LIST_BEGIN
//Usage
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
#if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
#endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>", "UserFilter<false, true>");
#else
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
#endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>");
#endif
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");
//Meta Usage
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::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
//System Usage
METHOD_ADD(api::Help, "/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::PruneUsers, "/v1/admin/prune_users", Post, "UserFilter<false, true>", "JsonFilter<true>"); //expects ["time"](int64) and ["amount"](uint32)
METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
//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"](uint32) ["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)
METHOD_LIST_END
};

View file

@ -1,139 +0,0 @@
#pragma once
#include <drogon/HttpController.h>
#include "bank.hpp"
using namespace drogon;
#define req_args const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback
#define JSON(V) callback(HttpResponse::newHttpJsonResponse(JsonReturn(V)));
#define INLINE __attribute__((always_inline)) inline
#define GEN_BODY \
const auto temp_req = req->getJsonObject(); \
const auto body = temp_req ? *temp_req : Json::Value();
template <typename T>
INLINE Json::Value JsonReturn(T &&val)
{
Json::Value res;
if constexpr (std::is_same_v<T, int_fast8_t>)
{
res["value"] = (int)val; //becuase of json lib interpreting 67 as 'A' for example
}
else if constexpr (std::is_same_v<T, long>)
{
res["value"] = (Json::Int64)val;
}
else
{
res["value"] = val;
}
return res;
}
class BankF : public HttpController<BankF, false>
{
public:
void Help(req_args) const
{
auto resp = HttpResponse::newHttpResponse();
auto handlerInfo = app().getHandlersInfo();
resp->setBody("<body> <h1>ALL FUNCTIONS (that have args) ARE EXPECTING JSON AS DATA TYPE</h1> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/close (POST)</h2> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - admin password</p> <blockquote> <p>Closes and Saves the server.</p> </blockquote> <h2>/BankF/user (POST)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of the user being added (must be less then 50 characters)</p> <p><span style=\"background-color: #808080;\">&nbsp;init_pass&nbsp;</span> - initial password for the user being added</p> <blockquote> <p>Adds a user to the bank</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (POST)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of the user being added</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - admin password required to add user with balance</p> <p><span style=\"background-color: #808080;\">&nbsp;init_bal&nbsp;</span> - initial balance for user being added</p> <p><span style=\"background-color: #808080;\">&nbsp;init_pass&nbsp;</span> - initial password for user being added</p> <blockquote> <p>Adds a user with initial balance</p> </blockquote> <h2>/BankF/sendfunds (POST)</h2> <p><span style=\"background-color: #808080;\">&nbsp;a_name&nbsp;</span> - sender's name</p> <p><span style=\"background-color: #808080;\">&nbsp;b_name&nbsp;</span> - reciever's name</p> <p><span style=\"background-color: #808080;\">&nbsp;amount&nbsp;</span> - amount being sent</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - password of sender</p> <blockquote> <p>Sends money from one user to another</p> </blockquote> <h2>/BankF/changepass (PATCH)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of user's password being changes</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - password of user being changed</p> <p><span style=\"background-color: #808080;\">&nbsp;new_pass&nbsp;</span> - new password to replace the current user's password</p> <blockquote> <p>Changes password of a user, returns -1 if user doesnt exist</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/{<span style=\"color: #339966;\">name</span>}/bal (PATCH)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - the name of the user being set</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - the admin password required</p> <p><span style=\"background-color: #808080;\">&nbsp;amount&nbsp;</span> - the new balance of the user</p> <blockquote> <p>Sets the balance of a user</p> </blockquote> <h2>/BankF/help (GET)</h2> <blockquote> <p>the page you're looking at right now!</p> </blockquote> <h2>/BankF/vpass (POST)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of user being verified</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - password being verified</p> <blockquote> <p>returns 0 or 1 based on if [attempt] is equal to the password of the user [name], or -1 if user does not exist. The intended usage for this function is for connected services</p> </blockquote> <h2>/BankF/contains/{<span style=\"color: #339966;\">name</span>} (GET)</h2> <blockquote> <p>returns a 0 or 1 based on if the bank contains the user</p> </blockquote> <h2>/BankF/{<span style=\"color: #339966;\">name</span>}/bal (GET)</h2> <blockquote> <p>returns the balance of a given user's name, if -1 that means the user does not exist</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/vpass (POST)</h2><p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - admin password</p> <blockquote> <p>Verifies if password entered is admin password</p> </blockquote> <h2>/BankF/{<span style=\"color: #339966;\">name</span>}/log (POST)</h2><p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - user password</p> <blockquote> <p>returns a list of last 100 transactions, -1 if user not found, 0 if invalid password</p> </blockquote><h2>/BankF/user (DELETE)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of user being deleted</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - password of user being deleted</p> <blockquote> <p>Deletes a user with the password of the user as verification</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (DELETE)</h2> <p><span style=\"background-color: #808080;\">&nbsp;name&nbsp;</span> - name of user being deleted</p> <p><span style=\"background-color: #808080;\">&nbsp;attempt&nbsp;</span> - admin password</p> <blockquote> <p>Deletes a user with admin password as verification</p> </blockquote> </body>");
resp->setExpiredTime(0);
callback(resp);
}
void Close(req_args) const
{
GEN_BODY
bool res;
if (body["attempt"].asCString() == bank.admin_pass)
{
bank.Save();
res = true;
app().quit();
}
else
{
res = false;
}
JSON(res);
}
void AddUser(req_args) const
{
GEN_BODY
JSON(bank.AddUser(body["name"].asCString(), body["init_pass"].asCString()));
}
void AdminAddUser(req_args) const
{
GEN_BODY
JSON(bank.AdminAddUser(body["attempt"].asCString(), body["name"].asCString(), body["init_bal"].asUInt(), body["init_pass"].asCString()));
}
void DelUser(req_args) const
{
GEN_BODY
JSON(bank.DelUser(body["name"].asCString(), body["attempt"].asCString()));
}
void AdminDelUser(req_args) const
{
GEN_BODY
JSON(bank.AdminDelUser(body["name"].asCString(), body["attempt"].asCString()));
}
void SendFunds(req_args) const
{
GEN_BODY
JSON(bank.SendFunds(body["a_name"].asCString(), body["b_name"].asCString(), body["amount"].asUInt(), body["attempt"].asCString()));
}
void ChangePassword(req_args) const
{
GEN_BODY
JSON(bank.ChangePassword(body["name"].asCString(), body["attempt"].asCString(), body["new_pass"].asCString()));
}
void Contains(req_args, const std::string &name) const
{
JSON(bank.Contains(name));
}
void GetBal(req_args, const std::string &name) const
{
JSON(bank.GetBal(name));
}
void VerifyPassword(req_args) const
{
GEN_BODY
JSON(bank.VerifyPassword(body["name"].asCString(), body["attempt"].asCString()));
}
void SetBal(req_args, const std::string &name) const
{
GEN_BODY
JSON(bank.SetBal(name, body["attempt"].asCString(), body["amount"].asUInt()));
}
void AdminVerifyPass(req_args)
{
GEN_BODY
JSON(bank.AdminVerifyPass(body["attempt"].asCString()));
}
void GetLog(req_args, const std::string &name)
{
GEN_BODY
JSON(bank.GetLogs(name, body["attempt"].asCString()));
}
METHOD_LIST_BEGIN
METHOD_ADD(BankF::Close, "/admin/close", Post, Options);
METHOD_ADD(BankF::AddUser, "/user", Post, Options);
METHOD_ADD(BankF::AdminAddUser, "/admin/user", Post, Options);
METHOD_ADD(BankF::SendFunds, "/sendfunds", Post, Options);
METHOD_ADD(BankF::ChangePassword, "/changepass", Patch, Options);
METHOD_ADD(BankF::SetBal, "/admin/{name}/bal", Patch, Options);
METHOD_ADD(BankF::Help, "/help", Get, Options);
METHOD_ADD(BankF::VerifyPassword, "/vpass", Post, Options);
METHOD_ADD(BankF::Contains, "/contains/{name}", Get, Options);
METHOD_ADD(BankF::GetBal, "/{name}/bal", Get, Options);
METHOD_ADD(BankF::AdminVerifyPass, "/admin/vpass", Post, Options);
METHOD_ADD(BankF::GetLog, "/{name}/log", Post, Options);
METHOD_ADD(BankF::DelUser, "/user", Delete, Options);
METHOD_ADD(BankF::AdminDelUser, "/admin/user", Delete, Options);
METHOD_LIST_END
};

12
include/bank_resp.h Normal file
View 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
View 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;
};

14
include/json_filter.h Normal file
View file

@ -0,0 +1,14 @@
#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>>
{
public:
virtual void doFilter(const HttpRequestPtr &,
FilterCallback &&,
FilterChainCallback &&) override;
};

31
include/log.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include <deque>
#include "ccash_config.hpp"
#include "change_flag.h"
#include "transaction.h"
#include "simdjson.h"
using namespace simdjson;
struct Log
{
private:
#if USE_DEPRECATED_ENDPOINTS
ChangeFlag<true> log_flag;
std::string log_snapshot = "null";
#endif
ChangeFlag<true> log_flag_v2;
std::string log_snapshot_v2 = "null";
public:
std::deque<Transaction> data;
#if USE_DEPRECATED_ENDPOINTS
std::string GetLogs(const std::string& name) noexcept;
#endif
std::string GetLogsV2() noexcept;
std::string GetLogsRange(size_t n, size_t m) noexcept;
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
};

View file

@ -1,41 +0,0 @@
#pragma once
#include <array>
#include <algorithm>
#include "log_consts.hpp"
#include "transactions.hpp"
struct Log
{
std::vector<Transaction> data;
uint32_t end = 0;
void AddTrans(Transaction &&v)
{
if (data.size() == end)
{
data.resize(data.size()+pre_log_size); //prefetching memory
}
for (uint32_t i = end; i > 0; --i)
{
data[i] = std::move(data[i - 1]);
}
data[0] = std::move(v);
if (end < max_log_size)
{
++end;
}
}
Json::Value Serialize() const
{
Json::Value res;
for (uint32_t i = 0; i < data.size() && data[i].amount; ++i)
{
res[i]["to"] = data[i].to;
res[i]["from"] = data[i].from;
res[i]["amount"] = data[i].amount;
res[i]["time"] = (Json::UInt64)data[i].time;
}
return res;
}
};
//[*][*][]

View file

@ -1,3 +0,0 @@
#pragma once
constexpr auto max_log_size = 100; //
constexpr auto pre_log_size = 10; //amount allocated in advance (for example 5 would allocate every 5 logs)

23863
include/simdjson.h Normal file

File diff suppressed because it is too large Load diff

15
include/str_intrusion.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <string>
/*
The intended use of this cursed class is in violating the encapsulation of std::string this class acts like std::string_view even though its stored in a std::string.
The reason this was needed is because sometimes we have a std::string_view instance and another library requires a const std::string& argument, forcing us to copy to a string before passing it, this copying is unnecessary.
*/
struct StrFromSV_Wrapper
{
std::string str;
StrFromSV_Wrapper() noexcept;
StrFromSV_Wrapper(std::string_view sv) noexcept;
~StrFromSV_Wrapper() noexcept;
};

15
include/transaction.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <string>
#include <cstdint>
#include <ctime>
struct Transaction
{
std::string counterparty = "";
bool receiving = false;
uint32_t amount = 0;
time_t time = 0;
Transaction() noexcept;
Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
};

View file

@ -1,21 +0,0 @@
#pragma once
#include <chrono>
#include <cstdint>
//42 bytes total
struct Transaction
{
std::string from = "", to = "";
uint32_t amount = 0;
uint64_t time = 0;
Transaction() = default;
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();
}
};

19
include/user.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "xxhash_str.h"
#include "bank_dom_final_models.h"
#include "log.h"
struct User
{
uint32_t balance;
XXH64_hash_t password;
#if MAX_LOG_SIZE > 0
Log log;
#endif
User(uint32_t init_bal, const std::string &init_pass) noexcept;
User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept;
User(const bank_dom::User &u) noexcept;
bank_dom::User Encode() const noexcept;
};

View file

@ -1,54 +0,0 @@
#pragma once
#include <json/json.h>
#include <string>
#include "log.hpp"
struct User
{
uint32_t balance = 0;
uint64_t password;
Log log;
/**
* @brief User constructor
*
* @param init_pass initial password
*/
User(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(uint32_t init_bal, std::string &&init_pass) : balance(init_bal), password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
/**
* @brief User Constructor for loading
*
* @param init_bal
* @param init_pass
*/
User(uint32_t init_bal, uint64_t init_pass, Json::Value&& log_j) : balance(init_bal), password(init_pass)
{
if(log_j.size())
{
log.data.resize(log_j.size()+pre_log_size);
log.end = log_j.size();
for(uint32_t i = 0; i < log_j.size(); ++i)
{
log.data[i] = std::move(Transaction(log_j[i]["from"].asCString(), log_j[i]["to"].asCString(), log_j[i]["balance"].asUInt()));
}
}
}
Json::Value Serialize() const
{
Json::Value res;
res["balance"] = (Json::UInt)balance;
res["password"] = (Json::UInt64)password;
res["log"] = log.Serialize();
return res;
}
};

16
include/user_filter.h Normal file
View file

@ -0,0 +1,16 @@
#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>>
{
public:
virtual void doFilter(const HttpRequestPtr &,
FilterCallback &&,
FilterChainCallback &&) override;
};

View file

@ -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);
@ -1920,7 +1920,7 @@ XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
XXH_FORCE_INLINE xxh_u32
XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
{
const xxh_u8* bEnd = input + len;
const xxh_u8* bEnd = input ? input + len : NULL;
xxh_u32 h32;
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
@ -2348,7 +2348,7 @@ XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align)
XXH_FORCE_INLINE xxh_u64
XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
{
const xxh_u8* bEnd = input + len;
const xxh_u8* bEnd = input ? input + len : NULL;
xxh_u64 h64;
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
@ -2546,7 +2546,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
return XXH_readBE64(src);
}
#ifndef XXH_NO_XXH3
/* *********************************************************************
* XXH3
@ -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;
@ -5312,6 +5312,8 @@ XXH128_hashFromCanonical(const XXH128_canonical_t* src)
#endif /* XXH_NO_LONG_LONG */
#endif /* XXH_NO_XXH3 */
/*!
* @}
*/

9
include/xxhash_str.h Normal file
View 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;
};

101
main.cpp
View file

@ -1,73 +1,124 @@
#include <iostream>
#include <chrono>
#include <thread>
#include <sys/types.h>
#include <unistd.h>
#include "bank_f.hpp"
#include "bank_api.h"
//sig handling headers
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
using namespace std::chrono;
//threads of cpu
#include <sys/sysinfo.h>
using namespace drogon;
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)
{
if (argc != 4)
{
std::cerr << "Usage: sudo ./bank <admin password> <saving frequency in minutes> <threads>\n";
static_assert(MAX_LOG_SIZE >= 0);
if (argc == 1)
{
std::ofstream users_save(users_location, std::ios::out | std::ios::binary);
if (users_save.is_open())
{
uint8_t temp[16]{16, 0, 0, 0, 4};
users_save.write((char *)temp, 16);
users_save.close();
std::cout << "User save file generated\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return 0;
}
else
{
std::cerr << "File cannot be created (may already exist)\n";
return -1;
}
}
if (argc < 3)
{
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return -1;
}
if (geteuid() != 0)
{
std::cerr << "ERROR: CCash MUST be ran as root\n";
return 0;
return -1;
}
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
std::cout
<< "\nAPI : v2.6.1\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() + saving_freq
<< "\nMulti threading : enabled";
#else
<< "\n\nThreads : " << 1 + saving_freq
<< "\nMulti threading : disabled";
#endif
//Loading users from users.json
bank.Load();
//Loading users from users.dat
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 * (75 + sizeof(Transaction) + max_name_size)) / 1048576 << "MB" //75:cached response per log(heap), sizeof(Transaction), max_name_size:counterparty(heap)
<< "\nLoaded " << Bank::SumBal() << " C$H"
<< 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 Password
bank.admin_pass = argv[1];
//Admin account
Bank::admin_account = argv[1];
//Auto Saving
const unsigned long saving_freq = std::stoul(argv[2]);
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
{
std::thread([saving_freq]() {
std::thread([saving_freq]()
{
while (1)
{
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';
std::cout << "Saving " << std::time(0) << "...\n" << Bank::Save();
}
}).detach();
})
.detach();
}
auto API = std::make_shared<BankF>();
app().registerPostHandlingAdvice(
[](const drogon::HttpRequestPtr &req, const drogon::HttpResponsePtr &resp) {
resp->addHeader("Access-Control-Allow-Origin", "*");
});
app().loadConfigFile("../config.json").registerController(API).setThreadNum(std::stoul(argv[3])).run();
if (argc == 4 && !strcmp(argv[3], "true")) { app().enableRunAsDaemon(); }
else if (argc == 4 && strcmp(argv[3], "false"))
{
std::cerr << "daemon flag must be \"true\" or \"false\"\n";
return -1;
}
} //destroying setup variables
app()
.loadConfigFile(config_location)
#if MULTI_THREADED
.setThreadNum(get_nprocs())
#endif
.run();
SaveSig(0);
return 0;
}

433
src/bank.cpp Normal file
View file

@ -0,0 +1,433 @@
#include "bank.h"
#if MULTI_THREADED
phmap::parallel_flat_hash_map<
std::string, User,
xxHashStringGen,
phmap::priv::hash_default_eq<std::string>,
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
4UL,
std::mutex>
Bank::users;
#else
phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> Bank::users;
#endif
#if CONSERVATIVE_DISK_SAVE
ChangeFlag<false> Bank::save_flag;
#endif
std::shared_mutex Bank::iter_lock;
std::string Bank::admin_account;
using namespace drogon;
#if CONSERVATIVE_DISK_SAVE
#define SET_CHANGES_ON save_flag.SetChangesOn()
#else
#define SET_CHANGES_ON
#endif
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 >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{
return false;
}
}
return true;
}
//NOT THREAD SAFE
size_t Bank::NumOfUsers() noexcept { return Bank::users.size(); }
//NOT THREAD SAFE
size_t Bank::NumOfLogs() noexcept
{
#if MAX_LOG_SIZE > 0
size_t res = 0;
for (const auto &u : users)
{
res += u.second.log.data.size();
}
return res;
#else
return 0;
#endif
}
//NOT THREAD SAFE
size_t Bank::SumBal() noexcept
{
size_t res = 0;
for (const auto &u : users)
{
res += u.second.balance;
}
return res;
}
BankResponse Bank::GetBal(const std::string &name) noexcept
{
uint32_t res = 0;
if (!ValidUsername(name) || !Bank::users.if_contains(name, [&res](const User &u) { res = u.balance; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return {k200OK, std::to_string(res)};
}
}
#if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
BankResponse Bank::GetLogs(const std::string &name) noexcept
{
BankResponse res;
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
#endif
BankResponse Bank::GetLogsV2(const std::string &name) noexcept
{
BankResponse res;
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogsV2()}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
BankResponse Bank::GetLogsRange(const std::string &name, size_t start, size_t length) noexcept
{
BankResponse res;
if (start >= MAX_LOG_SIZE)
{
return {k400BadRequest, "\"Invalid {start} index\""};
}
if (!length)
{
return {k400BadRequest, "\"Invalid {length}\""};
}
if (!Bank::users.modify_if(name, [&name, &res, start, length](User &u) { res = {k200OK, u.log.GetLogsRange(start, length)}; }))
{
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{iter_lock};
#if MAX_LOG_SIZE > 0
time_t current_time = time(NULL);
if (!Bank::users.modify_if(a_name, [current_time, &a_name, &b_name, &res, amount](User &a)
#else
if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a)
#endif
{
//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(b_name, false, 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
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
b.balance += amount;
b.log.AddTrans(a_name, true, amount, current_time);
});
#else
Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; });
#endif
SET_CHANGES_ON;
}
return res;
}
bool Bank::VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept
{
bool res = false;
Bank::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
{
SET_CHANGES_ON;
Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); });
}
BankResponse Bank::SetBal(const std::string &name, int64_t amount) noexcept
{
if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) {
amount -= u.balance;
u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{
SET_CHANGES_ON;
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 bal;
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, &amount](User &u) {
if (u.balance < (amount * -1)) { amount = -int64_t(u.balance); };
bal = u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{
SET_CHANGES_ON;
return {k200OK, std::to_string(bal)}; //may return new balance
}
else
{
return {k404NotFound, "\"User not found\""};
}
}
bool Bank::Contains(const std::string &name) noexcept
{
return ValidUsername(name) && Bank::users.contains(name);
}
#if MAX_LOG_SIZE > 0
BankResponse Bank::PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept
#else
BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept
#endif
{
std::unique_lock<std::shared_mutex> lock{iter_lock};
size_t deleted_count = 0;
#if RETURN_ON_DEL
uint32_t bal = 0;
#endif
for (const auto &u : users)
{
#if MAX_LOG_SIZE > 0
#if RETURN_ON_DEL
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) {
bal += u.balance;
#else
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) {
#endif
return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal);
#else
#if RETURN_ON_DEL
if (Bank::users.erase_if(u.first, [threshold_bal, &bal, &deleted_count](User &u) {
bal += u.balance;
#else
if (Bank::users.erase_if(u.first, [threshold_bal, &deleted_count](User &u) {
#endif
return (u.balance < threshold_bal);
#endif
}))
{
SET_CHANGES_ON;
++deleted_count;
}
}
#if RETURN_ON_DEL
if (bal)
{
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
}
#endif
return {k200OK, std::to_string(deleted_count)};
}
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{iter_lock};
if (Bank::users.try_emplace_l(
name, [](User &) {}, init_bal, init_pass))
{
SET_CHANGES_ON;
return {k204NoContent, std::nullopt};
}
else
{
return {k409Conflict, "\"User already exists\""};
}
}
BankResponse Bank::DelUser(const std::string &name) noexcept
{
std::shared_lock<std::shared_mutex> lock{iter_lock};
#if RETURN_ON_DEL
uint32_t bal;
if (Bank::users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) &&
bal)
{
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
}
#endif
if (ValidUsername(name) && Bank::users.erase(name))
{
SET_CHANGES_ON;
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
{
std::shared_lock<std::shared_mutex> lock{iter_lock};
#if RETURN_ON_DEL
uint32_t bal;
if (Bank::users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) &&
bal)
{
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
}
#endif
SET_CHANGES_ON;
Bank::users.erase(name);
}
//ONLY EVER BEING CALLED BY SAVE THREAD OR C-INTERUPT
const char *Bank::Save()
{
#if CONSERVATIVE_DISK_SAVE
if (save_flag.GetChangeState())
{
#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(Bank::users.size());
users_copy.keys.reserve(Bank::users.size());
{
std::unique_lock<std::shared_mutex> lock{iter_lock};
for (const auto &u : users)
{
Bank::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);
assert(writer.verify() && "Data is corrupted!");
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 to save file\n");
}
#if CONSERVATIVE_DISK_SAVE
save_flag.SetChangesOff();
return " to disk...\n";
}
else
{
return " no changes...\n";
}
#else
return " to disk...\n";
#endif
}
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
void Bank::Load()
{
std::ifstream users_load(users_location, std::ios::out | std::ios::binary);
if (!users_load.is_open())
{
throw std::invalid_argument("Cannot find save file, to generate a new one run \"sudo ./bank\" (warning: will override file if it already exists)\n");
}
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())
{
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)
{
Bank::users.try_emplace(users_global.keys[i], users_global.users[i]);
}
}

373
src/bank_api.cpp Normal file
View file

@ -0,0 +1,373 @@
#include "bank_api.h"
#define CACHE_FOREVER resp->setExpiredTime(0)
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
thread_local ondemand::parser parser;
#define SIMD_JSON_GEN \
simdjson::padded_string input(req->getBody()); \
ondemand::document doc;
#define RESPONSE_PARSE(R) \
auto resp = HttpResponse::newCustomHttpResponse(R); \
CORS; \
callback(resp)
#define RESPOND_TRUE \
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k204NoContent, std::nullopt}); \
CORS; \
CACHE_FOREVER; \
callback(resp)
#define NAME_PARAM req->getParameter("name")
//Usage
void api::GetBal(req_args, const std::string &name)
{
RESPONSE_PARSE(Bank::GetBal(name));
}
#if USE_DEPRECATED_ENDPOINTS
void api::GetLogs(req_args)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogs(NAME_PARAM));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
#endif
void api::GetLogsV2(req_args)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(NAME_PARAM));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::GetLogsRange(req_args, size_t start, size_t length)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsRange(NAME_PARAM, start, length));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::AdminGetLogs(req_args, const std::string& name)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(name));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::SendFunds(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name;
uint64_t amount; // as simdjson lacks .get(uint32_t support)
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
res = Bank::SendFunds(NAME_PARAM, name_val.str, amount);
}
}
RESPONSE_PARSE(std::move(res));
}
void api::VerifyPassword(req_args) { RESPOND_TRUE; }
//Meta Usage
void api::ChangePassword(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view pass;
if (doc["pass"].get(pass))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper pass_val(pass);
Bank::ChangePassword(NAME_PARAM, pass_val.str);
res = BankResponse{k204NoContent, std::nullopt};
}
}
RESPONSE_PARSE(std::move(res));
}
void api::AdminChangePassword(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name, pass;
if (doc["name"].get(name) || doc["pass"].get(pass))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
if (Bank::Contains(name_val.str))
{
StrFromSV_Wrapper pass_val(pass);
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)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name;
uint64_t amount;
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
res = Bank::SetBal(name_val.str, amount);
}
}
RESPONSE_PARSE(std::move(res));
}
void api::ImpactBal(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name;
int64_t amount;
if (doc["name"].get(name) || doc["amount"].get(amount))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
res = Bank::ImpactBal(name_val.str, amount);
}
}
RESPONSE_PARSE(std::move(res));
}
//System Usage
void api::Help(req_args)
{
auto resp = HttpResponse::newRedirectionResponse("https://github.com/EntireTwix/CCash/blob/main/README.md", k301MovedPermanently);
CACHE_FOREVER;
callback(resp);
}
void api::Close(req_args)
{
Bank::Save();
RESPOND_TRUE; //filter handles admin creds
app().quit();
}
void api::Contains(req_args, const std::string &name)
{
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)
{
RESPOND_TRUE; //filter handles admin creds
}
void api::ApiProperties(req_args)
{
std::string info = "{\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"add_user_open\":" + (ADD_USER_OPEN?"true":"false") + ",\"return_on_del\":" + (RETURN_ON_DEL?'\"' + std::string(return_account) + "\"":"null") + '}';
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)});
CORS;
CACHE_FOREVER;
callback(resp);
}
void api::PruneUsers(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
uint64_t amount;
#if MAX_LOG_SIZE > 0
int64_t time;
if (doc["time"].get(time) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
res = Bank::PruneUsers(time, amount);
}
#else
if (doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
res = Bank::PruneUsers(amount);
}
#endif
}
RESPONSE_PARSE(std::move(res));
}
void api::AddUser(req_args)
{
if constexpr (ADD_USER_OPEN)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name, pass;
if (doc["name"].get(name) || doc["pass"].get(pass))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
StrFromSV_Wrapper pass_val(pass);
res = Bank::AddUser(name_val.str, 0, pass_val.str);
}
}
RESPONSE_PARSE(std::move(res));
}
else
{
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"AddUser is Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
}
}
void api::AdminAddUser(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name;
uint64_t amount;
std::string_view pass;
if (doc["name"].get(name) || doc["amount"].get(amount) || doc["pass"].get(pass) || (amount > std::numeric_limits<uint32_t>::max()))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
StrFromSV_Wrapper pass_val(pass);
res = Bank::AddUser(name_val.str, amount, pass_val.str);
}
}
RESPONSE_PARSE(std::move(res));
}
void api::DelSelf(req_args)
{
Bank::DelSelf(NAME_PARAM);
RESPOND_TRUE;
}
void api::AdminDelUser(req_args)
{
SIMD_JSON_GEN;
BankResponse res;
if (parser.iterate(input).get(doc))
{
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
}
else
{
std::string_view name;
if (doc["name"].get(name))
{
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
}
else
{
StrFromSV_Wrapper name_val(name);
res = Bank::DelUser(name_val.str);
}
}
RESPONSE_PARSE(std::move(res));
}

26
src/bank_resp.cpp Normal file
View 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
View 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>;

38
src/json_filter.cpp Normal file
View file

@ -0,0 +1,38 @@
#include "json_filter.h"
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>;

168
src/log.cpp Normal file
View file

@ -0,0 +1,168 @@
#include "log.h"
void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept
{
#if USE_DEPRECATED_ENDPOINTS
log_flag.SetChangesOn();
#endif
log_flag_v2.SetChangesOn();
if (data.size() == MAX_LOG_SIZE)
{
data.pop_front();
}
data.emplace_back(counterparty_str, receiving, amount, time);
}
#if USE_DEPRECATED_ENDPOINTS
std::string Log::GetLogs(const std::string& name) noexcept
{
if (log_flag.GetChangeState() && data.size()) // if there are changes
{
log_snapshot.resize(0);
//re-generate snapshot
size_t predicted_size = ((57 + (2 * max_name_size)) * data.size()) + 1;
if (log_snapshot.capacity() < predicted_size)
{
log_snapshot.reserve(predicted_size);
}
log_snapshot = '['; //1
for (size_t i = 0; i < data.size(); ++i)
{
log_snapshot += "{\"to\":\""; //7
log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
log_snapshot += "\",\"amount\":"; //11
log_snapshot += std::to_string(data[i].amount); //10?
log_snapshot += ",\"time\":"; //8
log_snapshot += std::to_string(data[i].time); //10?
log_snapshot += "},"; //2
}
log_snapshot.back() = ']';
log_flag.SetChangesOff();
}
return log_snapshot;
}
#endif
std::string Log::GetLogsV2() noexcept
{
if (log_flag_v2.GetChangeState() && data.size()) // if there are changes
{
log_snapshot_v2.resize(0);
//re-generate snapshot
size_t predicted_size = ((59 + max_name_size) * data.size()) + 1;
if (log_snapshot_v2.capacity() < predicted_size)
{
log_snapshot_v2.reserve(predicted_size);
}
log_snapshot_v2 = '['; //1
for (size_t i = data.size(); i --> 0;)
{
log_snapshot_v2 += "{\"counterparty\":\""; //17
log_snapshot_v2 += data[i].counterparty; //max_name_size?
log_snapshot_v2 += "\",\"amount\":"; //11
if (!data[i].receiving) { log_snapshot_v2 += '-'; } //1
log_snapshot_v2 += std::to_string(data[i].amount); //10?
log_snapshot_v2 += ",\"time\":"; //8
log_snapshot_v2 += std::to_string(data[i].time); //10?
log_snapshot_v2 += "},"; //2
}
log_snapshot_v2.back() = ']';
log_flag_v2.SetChangesOff();
}
return log_snapshot_v2;
}
std::string Log::GetLogsRange(size_t start, size_t length) noexcept
{
if (start >= data.size()) { return "[]"; }
if (start == 0 && length == MAX_LOG_SIZE) { return log_snapshot_v2; }
if (log_flag_v2.GetChangeState() && data.size()) { GetLogsV2(); }
size_t log_index_n, i;
if (start < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "a\n";
i = 0;
log_index_n = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_n == start)
{
log_index_n = i;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_n;
}
}
else
{
// std::cout << "b\n";
i = log_snapshot_v2.size();
log_index_n = data.size();
while(i --> 0)
{
if (log_index_n == start)
{
log_index_n = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_n;
}
}
size_t log_index_m = std::string::npos;
if ((start + length) < data.size())
{
if (length < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "c\n";
log_index_m = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_m;
}
}
else
{
// std::cout << "d\n";
i = log_snapshot_v2.size();
log_index_m = data.size();
while(i --> 0)
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_m;
}
}
log_index_m -= log_index_n;
}
std::string res(log_snapshot_v2.substr(log_index_n, log_index_m));
res[0] = '[';
res[res.size() - 1] = ']';
// std::cout << res << '\n';
return res;
}

12032
src/simdjson.cpp Normal file

File diff suppressed because it is too large Load diff

45
src/str_intrusion.cpp Normal file
View 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);
}

4
src/transaction.cpp Normal file
View file

@ -0,0 +1,4 @@
#include "transaction.h"
Transaction::Transaction() noexcept {};
Transaction::Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {}

57
src/user.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "user.h"
/**
* @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) noexcept : balance(init_bal), password(xxHashStringGen{}(init_pass)) {}
/**
* @brief User Constructor for loading
*
* @param init_bal
* @param init_pass
*/
User::User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept : balance(init_bal), password(init_pass) {}
User::User(const bank_dom::User &u) noexcept : balance(u.balance), password(u.password)
{
#if MAX_LOG_SIZE > 0
if (u.logs)
{
uint32_t i = 0;
if (MAX_LOG_SIZE < u.logs.value().data.size())
{
i = (u.logs.value().data.size() - MAX_LOG_SIZE);
}
for (; i < u.logs.value().data.size(); ++i)
{
const bank_dom::Transaction &temp = u.logs.value().data[i];
log.data.emplace_front(temp.counterparty, temp.receiving, temp.amount, temp.time);
}
}
#endif
}
bank_dom::User User::Encode() const noexcept
{
#if MAX_LOG_SIZE > 0
if (this->log.data.size())
{
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.counterparty, t.receiving, t.amount, t.time);
}
return bank_dom::User(balance, password, save_log);
}
else
{
return bank_dom::User(balance, password, std::nullopt);
}
#else
return bank_dom::User(balance, password, std::nullopt);
#endif
}

75
src/user_filter.cpp Normal file
View file

@ -0,0 +1,75 @@
#include "user_filter.h"
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 >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{
return false;
}
}
return true;
}
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::admin_account == 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
View 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

@ -0,0 +1 @@
Subproject commit eaebee8f666ea0451b0474e7be16006ad994004c