Compare commits

...

10 commits

Author SHA1 Message Date
79ac12a4d7 Update
Some checks failed
cserver CMake / tidy (push) Has been cancelled
cserver CMake / format (push) Has been cancelled
cserver CMake / build (Release, clang-18, clang++-18, ubuntu-24.04) (push) Has been cancelled
cserver CMake / build (Release, gcc-14, g++-14, ubuntu-24.04) (push) Has been cancelled
2024-08-30 09:07:59 +00:00
Daniil Zhukov
42a15457ec add doxygen layout 2024-07-09 01:31:02 +00:00
Daniil Zhukov
fb6eb84c9e add awesome doxygen style 2024-07-09 01:31:02 +00:00
Daniil Zhukov
c3f1d7ffe7 remove boost and impl from docs 2024-07-09 01:31:02 +00:00
Daniil Zhukov
c513d24565 build: doxygen generate docs 2024-07-09 01:31:02 +00:00
42a20bcc41 Fix bug in cli manager 2024-07-08 02:43:21 +00:00
87bfb71f2b Add trace logs to InitComponents 2024-07-08 02:41:22 +00:00
c319ee20eb Remove loopholes check in cmake 2024-07-08 01:45:04 +00:00
0e2e1bf8d0 Use custom IsConstant instead __builtin_constant_p 2024-07-07 22:59:15 +00:00
cfb5f82948 Add __builtin_constant_p for gcc build without optimizations 2024-07-07 03:59:11 +00:00
18 changed files with 6495 additions and 52 deletions

2
.gitignore vendored
View file

@ -18,3 +18,5 @@ cmake/CPM.cmake
cpm-package-lock.cmake cpm-package-lock.cmake
include/openssl include/openssl
include/tls.h include/tls.h
libcserver_shared.so
libcserver_static.a

View file

@ -7,6 +7,7 @@ set(CXX_EXTENSIONS NO)
set(Boost_USE_MULTITHREADED ON) set(Boost_USE_MULTITHREADED ON)
set(BOOST_NOT_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED "url;program_options") set(BOOST_NOT_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED "url;program_options")
set(BOOST_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED "asio;pfr") set(BOOST_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED "asio;pfr")
set(UTEMPL_MODULE OFF)
set(TRY_BOOST_VERSION "1.85.0") set(TRY_BOOST_VERSION "1.85.0")
set(BOOST_INCLUDE_LIBRARIES set(BOOST_INCLUDE_LIBRARIES
"${BOOST_NOT_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED};${BOOST_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED}" "${BOOST_NOT_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED};${BOOST_HEADER_ONLY_COMPONENTS_THAT_YOU_NEED}"
@ -14,6 +15,7 @@ set(BOOST_INCLUDE_LIBRARIES
option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON) option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON)
option(CSERVER_USE_LIBRESSL "Use LibreSSL" OFF) option(CSERVER_USE_LIBRESSL "Use LibreSSL" OFF)
option(UTEMPL_USE_LOCAL_PACKAGE "Use utempl local package" OFF)
file( file(
DOWNLOAD DOWNLOAD
@ -69,11 +71,16 @@ CPMAddPackage(
endif() endif()
set(TMP ${CPM_USE_LOCAL_PACKAGES})
set(CPM_USE_LOCAL_PACKAGES ${UTEMPL_USE_LOCAL_PACKAGE})
CPMAddPackage( CPMAddPackage(
NAME utempl NAME utempl
URL "https://github.com/linuxnyasha/utempl/archive/refs/heads/main.zip" URL "https://github.com/linuxnyasha/utempl/archive/refs/heads/main.zip"
EXCLUDE_FROM_ALL ON
OPTIONS "ENABLE_TESTS OFF" "ENABLE_EXAMPLES OFF" OPTIONS "ENABLE_TESTS OFF" "ENABLE_EXAMPLES OFF"
) )
set(CPM_USE_LOCAL_PACKAGES ${TMP})

View file

@ -1,5 +1,10 @@
VERSION = $(shell git describe --tags --always --long)
MAKEFILE_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) MAKEFILE_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTS_BIN = $(MAKEFILE_DIR)/build/cserver_tests BUILD_DIR = $(MAKEFILE_DIR)/build
TESTS_BIN = $(BUILD_DIR)/cserver_tests
DOXYGEN ?= doxygen
CC = clang CC = clang
CXX = clang++ CXX = clang++
@ -75,6 +80,13 @@ tidy: build/.ran-cmake
$(shell find examples -name *.cpp) \ $(shell find examples -name *.cpp) \
$(shell find tests -name *.cpp) $(shell find tests -name *.cpp)
docs:
@( \
cat docs/doxygen.conf; \
echo PROJECT_NUMBER=$(VERSION); \
echo OUTPUT_DIRECTORY=$(BUILD_DIR)/docs \
) | $(DOXYGEN) -
FORCE: ; FORCE: ;
.PHONY: all cmake test format clean distclean .PHONY: all cmake format test tidy docs clean distclean

View file

@ -1,29 +0,0 @@
#include <tuple>
#include <utempl/loopholes/core.hpp>
#include <utempl/type_list.hpp>
struct SomeStruct {
constexpr SomeStruct(auto&& arg) {
arg.Method(42);
};
};
struct Injector {
template <typename T, auto _ = utempl::loopholes::Injector<0, utempl::TypeList<T>{}>{}>
auto Method(T&&) const -> void;
};
template <typename T, auto... Args>
inline constexpr auto Use() {
std::ignore = T{Args...};
};
template <typename...>
consteval auto Ignore() {};
auto main() -> int {
Ignore<decltype(Use<SomeStruct, Injector{}>())>();
static_assert(std::is_same_v<decltype(Magic(utempl::loopholes::Getter<0>{})), utempl::TypeList<int>>);
};

View file

@ -2,9 +2,3 @@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components("@PROJECT_NAME@") check_required_components("@PROJECT_NAME@")
try_compile(loopholes_body_inject
SOURCES "${CMAKE_CURRENT_LIST_DIR}/check.cpp")
if(NOT loopholes_body_inject)
message(FATAL_ERROR "The Compiler Doesn't Support Retrieval Of Information Via Loopholes. If You Are Using gcc, Enable Optimizations.")
endif()

View file

@ -0,0 +1,157 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);

View file

@ -0,0 +1,85 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
constructor() {
super();
this.onclick=this.copyContent
}
static title = "Copy to clipboard"
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`
static successDuration = 980
static init() {
$(function() {
$(document).ready(function() {
if(navigator.clipboard) {
const fragments = document.getElementsByClassName("fragment")
for(const fragment of fragments) {
const fragmentWrapper = document.createElement("div")
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
fragmentWrapper.appendChild(fragment)
fragmentWrapper.appendChild(fragmentCopyButton)
}
}
})
})
}
copyContent() {
const content = this.previousSibling.cloneNode(true)
// filter out line number from file listings
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
node.remove()
})
let textContent = content.textContent
// remove trailing newlines that appear in file listings
let numberOfTrailingNewlines = 0
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
numberOfTrailingNewlines++;
}
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
navigator.clipboard.writeText(textContent);
this.classList.add("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
window.setTimeout(() => {
this.classList.remove("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
}, DoxygenAwesomeFragmentCopyButton.successDuration);
}
}
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)

View file

@ -0,0 +1,81 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeInteractiveToc {
static topOffset = 38
static hideMobileMenu = true
static headers = []
static init() {
window.addEventListener("load", () => {
let toc = document.querySelector(".contents > .toc")
if(toc) {
toc.classList.add("interactive")
if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) {
toc.classList.add("open")
}
document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => {
if(toc.classList.contains("open")) {
toc.classList.remove("open")
} else {
toc.classList.add("open")
}
})
document.querySelectorAll(".contents > .toc > ul a").forEach((node) => {
let id = node.getAttribute("href").substring(1)
DoxygenAwesomeInteractiveToc.headers.push({
node: node,
headerNode: document.getElementById(id)
})
document.getElementById("doc-content")?.addEventListener("scroll", () => {
DoxygenAwesomeInteractiveToc.update()
})
})
DoxygenAwesomeInteractiveToc.update()
}
})
}
static update() {
let active = DoxygenAwesomeInteractiveToc.headers[0]?.node
DoxygenAwesomeInteractiveToc.headers.forEach((header) => {
let position = header.headerNode.getBoundingClientRect().top
header.node.classList.remove("active")
header.node.classList.remove("aboveActive")
if(position < DoxygenAwesomeInteractiveToc.topOffset) {
active = header.node
active?.classList.add("aboveActive")
}
})
active?.classList.add("active")
active?.classList.remove("aboveActive")
}
}

View file

@ -0,0 +1,51 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeParagraphLink {
// Icon from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static icon = `<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 24 24" width="20px"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z"/></svg>`
static title = "Permanent Link"
static init() {
$(function() {
$(document).ready(function() {
document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => {
let anchorlink = document.createElement("a")
anchorlink.setAttribute("href", `#${node.getAttribute("id")}`)
anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title)
anchorlink.classList.add("anchorlink")
node.classList.add("anchor")
anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon
node.parentElement.appendChild(anchorlink)
})
})
})
}
}

View file

@ -0,0 +1,40 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
@media screen and (min-width: 768px) {
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
}
}

View file

@ -0,0 +1,116 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
html {
/* side nav width. MUST be = `TREEVIEW_WIDTH`.
* Make sure it is wide enough to contain the page title (logo + title + version)
*/
--side-nav-fixed-width: 335px;
--menu-display: none;
--top-height: 120px;
--toc-sticky-top: -25px;
--toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px);
}
#projectname {
white-space: nowrap;
}
@media screen and (min-width: 768px) {
html {
--searchbar-background: var(--page-background-color);
}
#side-nav {
min-width: var(--side-nav-fixed-width);
max-width: var(--side-nav-fixed-width);
top: var(--top-height);
overflow: visible;
}
#nav-tree, #side-nav {
height: calc(100vh - var(--top-height)) !important;
}
#nav-tree {
padding: 0;
}
#top {
display: block;
border-bottom: none;
height: var(--top-height);
margin-bottom: calc(0px - var(--top-height));
max-width: var(--side-nav-fixed-width);
overflow: hidden;
background: var(--side-nav-background);
}
#main-nav {
float: left;
padding-right: 0;
}
.ui-resizable-handle {
cursor: default;
width: 1px !important;
background: var(--separator-color);
box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
}
#nav-path {
position: fixed;
right: 0;
left: var(--side-nav-fixed-width);
bottom: 0;
width: auto;
}
#doc-content {
height: calc(100vh - 31px) !important;
padding-bottom: calc(3 * var(--spacing-large));
padding-top: calc(var(--top-height) - 80px);
box-sizing: border-box;
margin-left: var(--side-nav-fixed-width) !important;
}
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
}
#MSearchResultsWindow {
left: var(--spacing-medium) !important;
right: auto;
}
}

View file

@ -0,0 +1,90 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeTabs {
static init() {
window.addEventListener("load", () => {
document.querySelectorAll(".tabbed:not(:empty)").forEach((tabbed, tabbedIndex) => {
let tabLinkList = []
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
tab.id = "tab_" + tabbedIndex + "_" + tabIndex
let header = tab.querySelector(".tab-title")
let tabLink = document.createElement("button")
tabLink.classList.add("tab-button")
tabLink.appendChild(header)
header.title = header.textContent
tabLink.addEventListener("click", () => {
tabbed.querySelectorAll(":scope > ul > li").forEach((tab) => {
tab.classList.remove("selected")
})
tabLinkList.forEach((tabLink) => {
tabLink.classList.remove("active")
})
tab.classList.add("selected")
tabLink.classList.add("active")
})
tabLinkList.push(tabLink)
if(tabIndex == 0) {
tab.classList.add("selected")
tabLink.classList.add("active")
}
})
let tabsOverview = document.createElement("div")
tabsOverview.classList.add("tabs-overview")
let tabsOverviewContainer = document.createElement("div")
tabsOverviewContainer.classList.add("tabs-overview-container")
tabLinkList.forEach((tabLink) => {
tabsOverview.appendChild(tabLink)
})
tabsOverviewContainer.appendChild(tabsOverview)
tabbed.before(tabsOverviewContainer)
function resize() {
let maxTabHeight = 0
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
let visibility = tab.style.display
tab.style.display = "block"
maxTabHeight = Math.max(tab.offsetHeight, maxTabHeight)
tab.style.display = visibility
})
tabbed.style.height = `${maxTabHeight + 10}px`
}
resize()
new ResizeObserver(resize).observe(tabbed)
})
})
}
static resize(tabbed) {
}
}

File diff suppressed because it is too large Load diff

2865
docs/doxygen.conf Normal file

File diff suppressed because it is too large Load diff

247
docs/layout.xml Normal file
View file

@ -0,0 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.11.0 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title="Home"/>
<tab type="usergroup" title="Documentation">
<!-- Put here all custom documentation pages -->
</tab>
<tab type="usergroup" visible="yes" title="Reference">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
<tab type="examples" visible="yes" title="" intro=""/>
<tab type="pages" visible="no" title="" intro=""/>
</tab>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<inheritancegraph visible="yes"/>
<collaborationgraph visible="yes"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<concepts visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<properties title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<properties title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a concept page -->
<concept>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<definition visible="yes" title=""/>
<detaileddescription title=""/>
<authorsection visible="yes"/>
</concept>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="yes"/>
<includedbygraph visible="yes"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<properties title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<properties title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="yes"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<modules visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a C++20 module page -->
<module>
<briefdescription visible="yes"/>
<exportedmodules visible="yes"/>
<memberdecl>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<enums title=""/>
<typedefs title=""/>
<functions title=""/>
<variables title=""/>
<membergroups title=""/>
</memberdecl>
<detaileddescription title=""/>
<memberdecl>
<files visible="yes"/>
</memberdecl>
</module>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

View file

@ -5,7 +5,7 @@
struct SomeStruct { struct SomeStruct {
static_assert(utempl::OpenStruct<SomeStruct>()); static_assert(utempl::OpenStruct<SomeStruct>());
utempl::FieldAttribute<std::string, cserver::cli::Name<"field,f">> field; utempl::FieldAttribute<std::string, utempl::TypeList<cserver::cli::Name<"field,f">>> field;
static_assert(utempl::CloseStruct<SomeStruct>()); static_assert(utempl::CloseStruct<SomeStruct>());
}; };

View file

@ -74,10 +74,11 @@ struct Manager {
constexpr std::string_view nname = nnname.substr(0, nnname.find(',')); constexpr std::string_view nname = nnname.substr(0, nnname.find(','));
utempl::ConstexprString<nname.size() + 1> name; utempl::ConstexprString<nname.size() + 1> name;
std::ranges::copy_n(nname.begin(), nname.size(), name.begin()); std::ranges::copy_n(nname.begin(), nname.size(), name.begin());
name.data[nname.size()] = '\0';
if(this->variableMap.count(name.begin())) { if(this->variableMap.count(name.begin())) {
return this->variableMap[name.begin()].template as<typename decltype(fieldConfig)::Type>(); return this->variableMap[name.begin()].template as<typename decltype(fieldConfig)::Type>();
}; };
throw std::runtime_error(fmt::format("Not found cli option {}", name)); throw std::runtime_error(fmt::format("Not found cli option {}", name.begin()));
}()...}; }()...};
} | utempl::kSeq<utempl::kTupleSize<decltype(fieldConfigs)>>; } | utempl::kSeq<utempl::kTupleSize<decltype(fieldConfigs)>>;
}; };

View file

@ -2,6 +2,7 @@
#include <cxxabi.h> #include <cxxabi.h>
#include <boost/core/demangle.hpp> #include <boost/core/demangle.hpp>
#include <cserver/components/logger.hpp>
#include <cserver/engine/basic/task_processor.hpp> #include <cserver/engine/basic/task_processor.hpp>
#include <cserver/engine/coroutine.hpp> #include <cserver/engine/coroutine.hpp>
#include <utempl/loopholes/counter.hpp> #include <utempl/loopholes/counter.hpp>
@ -187,21 +188,46 @@ inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> vo
static utempl::Tuple inited = static utempl::Tuple inited =
TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges<AsyncConditionVariable, DependencyGraph>(ioContext); TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges<AsyncConditionVariable, DependencyGraph>(ioContext);
auto work = make_work_guard(ioContext); auto work = make_work_guard(ioContext);
[]<std::size_t... Is>(std::index_sequence<Is...>) { [](auto... is) {
// clang-format off // clang-format off
(boost::asio::co_spawn(ioContext, []() -> cserver::Task<> { (boost::asio::co_spawn(ioContext, [](auto is) -> cserver::Task<> {
using Current = decltype(Get<Is>(decltype(T::kUtils)::kComponentConfigs)); using Current = decltype(Get<is>(decltype(T::kUtils)::kComponentConfigs));
auto& dependencies = Get<Is>(inited); auto& dependencies = Get<is>(inited);
constexpr auto logLevel = T::kConfig.template Get<"logging">().template Get<"level">();
if constexpr(logLevel == LoggingLevel::kTrace) {
fmt::println("[TRACE] Started coroutine for initialisation component {} with flag address {}",
static_cast<std::string_view>(Current::kName),
static_cast<void*>(&GetInitFlagFor<AsyncConditionVariable, is>(ioContext)));
};
for(auto* flag : dependencies) { for(auto* flag : dependencies) {
if constexpr(logLevel == LoggingLevel::kTrace) {
fmt::println("[TRACE] {} Component: Waiting flag on address {}",
static_cast<std::string_view>(Current::kName),
static_cast<void*>(flag));
};
co_await flag->AsyncWait(); co_await flag->AsyncWait();
if constexpr(logLevel == LoggingLevel::kTrace) {
fmt::println("[TRACE] {} Component: Waited flag on address {}",
static_cast<std::string_view>(Current::kName),
static_cast<void*>(flag));
};
}; };
try { try {
if constexpr(Current::kName == cliArgs) { if constexpr(Current::kName == cliArgs) {
ServiceContextForComponentWithCliArgs<Current, T> currentContext{context, argc, argv}; ServiceContextForComponentWithCliArgs<Current, T> currentContext{context, argc, argv};
Get<Is>(context.storage).emplace(currentContext); if constexpr(logLevel == LoggingLevel::kTrace) {
fmt::println("[TRACE] {} Component: call constructor with cli args",
static_cast<std::string_view>(Current::kName));
};
Get<is>(context.storage).emplace(currentContext);
} else { } else {
ServiceContextForComponent<Current, T> currentContext{context}; ServiceContextForComponent<Current, T> currentContext{context};
Get<Is>(context.storage).emplace(currentContext); if constexpr(logLevel == LoggingLevel::kTrace) {
fmt::println("[TRACE] {} Component: call constructor",
static_cast<std::string_view>(Current::kName));
};
Get<is>(context.storage).emplace(currentContext);
}; };
} catch(std::exception& error) { } catch(std::exception& error) {
auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name()); auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name());
@ -217,14 +243,18 @@ inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> vo
typeName); typeName);
ioContext.stop(); ioContext.stop();
}; };
auto& componentInitFlag = GetInitFlagFor<AsyncConditionVariable, Is>(ioContext); auto& componentInitFlag = GetInitFlagFor<AsyncConditionVariable, is>(ioContext);
componentInitFlag.NotifyAll(); if constexpr(logLevel == LoggingLevel::kTrace) {
if constexpr(requires{Get<Is>(context.storage)->Run();}) { fmt::println("[TRACE] {} Component: notify",
Get<Is>(context.storage)->Run(); static_cast<std::string_view>(Current::kName));
}; };
}(), boost::asio::detached), ...); componentInitFlag.NotifyAll();
if constexpr(requires{Get<is>(context.storage)->Run();}) {
Get<is>(context.storage)->Run();
};
}(is), boost::asio::detached), ...);
// clang-format on // clang-format on
}(std::make_index_sequence<utempl::kTupleSize<decltype(DependencyGraph)>>()); } | utempl::kSeq<utempl::kTupleSize<decltype(DependencyGraph)>>;
}; };
template <typename... Ts> template <typename... Ts>
@ -334,9 +364,26 @@ namespace impl {
template <typename Current, std::size_t I> template <typename Current, std::size_t I>
struct DependencyInfoKey {}; struct DependencyInfoKey {};
template <auto F>
consteval auto IsConstantImpl(...) {
return false;
};
template <auto F, auto = (F(), 1)>
consteval auto IsConstantImpl(bool) {
return true;
};
template <auto F>
consteval auto IsConstant() -> bool {
return IsConstantImpl<F>(true); // NOLINT
};
template <typename T, auto... Args> template <typename T, auto... Args>
inline constexpr auto Use() { inline constexpr auto Use() {
std::ignore = T{Args...}; std::ignore = IsConstant<[] {
T{Args...};
}>();
}; };
template <typename...> template <typename...>