From bac8a5d2822835cf47175d1162030653fadd5c09 Mon Sep 17 00:00:00 2001
From: johannst On Provide a single entry point The main mechanic can be explained with the following reduced example. If one
@@ -781,7 +781,7 @@ struct A {
struct B {};
-static_assert(is_valid<A>::value, "is true");
+static_assert(is_valid<A>::value, "is true");
// * Compare template arg list with primary template, we only supplied one
// arg, the second one will be defaulted as
// is_valid<A, void>
@@ -795,7 +795,7 @@ static_assert(is_valid<A>::value, "is true");
// * Specialization (2) matches <A, void>
// * Pick the most specialized version -> (2)
-static_assert(!is_valid<B>::value, "is false");
+static_assert(!is_valid<B>::value, "is false");
// * Compare template arg list with primary template, we only supplied one
// arg, the second one will be defaulted as
// is_valid<A, void>
@@ -846,7 +846,7 @@ struct pair<int, int> {
};
int main() {
- static_assert(pair<int>::kind == kIntBool, "");
+ static_assert(pair<int>::kind == kIntBool, "");
// * Compare template arg list with primary template, we only supplied one
// arg, the second one will be defaulted as
// pair<int, bool>
@@ -858,7 +858,7 @@ int main() {
// * (4) <int, bool> pattern does not match
// * Pick the most specialized version -> (3)
- static_assert(pair<char, char>::kind == kTT, "");
+ static_assert(pair<char, char>::kind == kTT, "");
// * Compare template arg list against available specializations, this will
// try to match the pattern <char, char> against the patterns defined in the
// partial specializations.
@@ -867,7 +867,7 @@ int main() {
// * (4) <char, char> pattern does not match
// * Pick the most specialized version -> (2)
- static_assert(pair<int, int>::kind == kIntInt, "");
+ static_assert(pair<int, int>::kind == kIntInt, "");
// * Compare template arg list against available specializations, this will
// try to match the pattern <int, int> against the patterns defined in the
// partial specializations.
@@ -876,7 +876,7 @@ int main() {
// * (4) <int, int> pattern does not match
// * Pick the most specialized version -> (3)
- static_assert(pair<char, short>::kind == kPrimary, "");
+ static_assert(pair<char, short>::kind == kPrimary, "");
// * Compare template arg list against available specializations, this will
// try to match the pattern <char, short> against the patterns defined in the
// partial specializations.
@@ -897,25 +897,25 @@ struct S {};
struct M {
M() {
- std::puts("M()");
+ std::puts("M()");
}
M(const M&) {
- std::puts("M(M&)");
+ std::puts("M(M&)");
}
M(M&&) {
- std::puts("M(M&&)");
+ std::puts("M(M&&)");
}
M& operator=(const M&) = delete;
M& operator=(M&&) = delete;
M(S&, int) {
- std::puts("M(S&)");
+ std::puts("M(S&)");
}
M(S&&, int) {
- std::puts("M(S&&)");
+ std::puts("M(S&&)");
}
~M() {
- std::puts("~M()");
+ std::puts("~M()");
}
};
@@ -963,11 +963,11 @@ struct option {
};
int main() {
- std::puts("==> case 1");
+ std::puts("==> case 1");
// invokes M(S&&, int)
option<M> opt1(S{}, 123);
- std::puts("==> case 2");
+ std::puts("==> case 2");
// invokes M() + M(M&&)
option<M> x /* option(M&&) + M(M&&) */ = M{} /* M() */;
}
diff --git a/development/cmake.html b/development/cmake.html
index b69f893..85ed59f 100644
--- a/development/cmake.html
+++ b/development/cmake.html
@@ -203,7 +203,7 @@ target_compile_definitions(liba INTERFACE DEF_INTERFACE)
add_executable(main main.cc)
target_link_libraries(main liba)
-gcc
strict aliasing is enabled starting with -O2
.for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done
+
for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done
-O0 -fstrict-aliasing [disabled]
-O1 -fstrict-aliasing [disabled]
-O2 -fstrict-aliasing [enabled]
@@ -379,13 +379,13 @@ to violate self defined contract, see
// Base case with one parameter.
template<int P>
void show_int() {
- printf("%d\n", P);
+ printf("%d\n", P);
}
// General case with at least two parameters, to disambiguate from base case.
template<int P0, int P1, int... Params>
void show_int() {
- printf("%d, ", P0);
+ printf("%d, ", P0);
show_int<P1, Params...>();
}
@@ -400,13 +400,13 @@ void show(const T& t) {
// General case with at least two parameters, to disambiguate from base case.
template<typename T0, typename T1, typename... Types>
void show(const T0& t0, const T1& t1, const Types&... types) {
- std::cout << t0 << ", ";
+ std::cout << t0 << ", ";
show(t1, types...);
}
int main() {
show_int<1, 2, 3, 4, 5>();
- show(1, 1.0, "foo", 'a');
+ show(1, 1.0, "foo", 'a');
}
Forwarding reference (fwd ref)
@@ -456,21 +456,21 @@ void fwd_wrapper(T&& param) { // forwarding reference
int main() {
{
- std::puts("==> wrapper rvalue reference");
+ std::puts("==> wrapper rvalue reference");
wrapper(M{});
// calls use(M&).
- std::puts("==> wrapper lvalue reference");
+ std::puts("==> wrapper lvalue reference");
struct M m;
wrapper(m);
// calls use(M&).
}
{
- std::puts("==> fwd_wrapper rvalue reference");
+ std::puts("==> fwd_wrapper rvalue reference");
fwd_wrapper(M{});
// calls use(M&&).
- std::puts("==> fwd_wrapper lvalue reference");
+ std::puts("==> fwd_wrapper lvalue reference");
struct M m;
fwd_wrapper(m);
// calls use(M&).
@@ -496,8 +496,8 @@ struct any_of<T, U0, U...> : any_of<T, U...> {};
template<typename T, typename... U>
constexpr bool any_of_v = any_of<T, U...>::value;
-static_assert(any_of_v<int, char, bool, int>, "");
-static_assert(!any_of_v<int, char, bool, float>, "");
+static_assert(any_of_v<int, char, bool, int>, "");
+static_assert(!any_of_v<int, char, bool, float>, "");
Example: SFINAE (enable_if)
Invoke
to call some Operations
.
@@ -543,16 +543,16 @@ namespace impl {
template<typename Ctx, template<typename> class Op, typename... P,
enable_if_bool<has_dst<Op<Ctx>>> = true>
void Invoke(const Ctx& C, P... params) {
- std::cout << "Invoke " << Op<Ctx>::Name << '\n';
+ std::cout << "Invoke " << Op<Ctx>::Name << '\n';
typename Op<Ctx>::Return R = impl::Invoke<Ctx, Op>(C, params...);
- std::cout << "returned -> " << R << '\n';
+ std::cout << "returned -> " << R << '\n';
}
// Invoke an OPERATION which has *NOT* a DESTINATION with arbitrary number of arguments.
template<typename Ctx, template<typename> class Op, typename... P,
disable_if_bool<has_dst<Op<Ctx>>> = true>
void Invoke(const Ctx& C, P... params) {
- std::cout << "Invoke " << Op<Ctx>::Name << " without destination." << '\n';
+ std::cout << "Invoke " << Op<Ctx>::Name << " without destination." << '\n';
impl::Invoke<Ctx, Op>(C, params...);
}
@@ -560,7 +560,7 @@ void Invoke(const Ctx& C, P... params) {
struct Ctx {
void out(const char* s, unsigned v) const {
- printf("%s%x\n", s, v);
+ printf("%s%x\n", s, v);
}
};
@@ -570,7 +570,7 @@ template<typename Ctx>
struct OpA {
using HasCtx = std::false_type;
using Return = int;
- static constexpr const char* const Name = "OpA";
+ static constexpr const char* const Name = "OpA";
constexpr Return operator()(int a, int b) const {
return a + b;
@@ -581,10 +581,10 @@ template<typename Ctx>
struct OpB {
using HasCtx = std::true_type;
using Return = void;
- static constexpr const char* const Name = "OpB";
+ static constexpr const char* const Name = "OpB";
Return operator()(const Ctx& C, unsigned a) const {
- C.out("a = ", a);
+ C.out("a = ", a);
}
};
@@ -650,7 +650,7 @@ struct registry {
const auto it = m_fns.find(nm);
if (it == m_fns.end()) {
static_assert(std::is_default_constructible_v<RET>,
- "RET must be default constructible");
+ "RET must be default constructible");
return {};
}
return std::invoke(it->second, p...);
@@ -661,7 +661,7 @@ struct registry {
static bool regfn_##REGISTRY##NAME() { \
const bool r = REGISTRY::get().add(#NAME, NAME); \
if (!r) { \
- std::puts("Failed to register test " #NAME ", same name already registered!"); \
+ std::puts("Failed to register test " #NAME ", same name already registered!"); \
std::abort(); \
} \
return r; \
@@ -677,10 +677,10 @@ struct registry {
using REG1 = registry<void>;
TEST(REG1, test1) {
- std::puts("REG1::test1");
+ std::puts("REG1::test1");
}
TEST(REG1, test2) {
- std::puts("REG1::test2");
+ std::puts("REG1::test2");
}
// -- Usage 2 with convenience macro wrapper.
@@ -689,18 +689,18 @@ using REG2 = registry<void, bool>;
#define TEST2(NAME, ...) TEST(REG2, NAME, ##__VA_ARGS__)
TEST2(test1, bool val) {
- printf("REG2::test1 val %d\n", val);
+ printf("REG2::test1 val %d\n", val);
}
int main() {
const auto& R1 = REG1::get();
R1.dump();
- R1.invoke("test1");
- R1.invoke("test2");
+ R1.invoke("test1");
+ R1.invoke("test2");
const auto& R2 = REG2::get();
R2.dump();
- R2.invoke("test1", true);
+ R2.invoke("test1", true);
return 0;
}
@@ -757,7 +757,7 @@ struct Entry {
};
int main() {
- static_assert(is_entry_v<Entry<bool>>, "");
+ static_assert(is_entry_v<Entry<bool>>, "");
}
> touch liba.cc; echo "int main() {}" > main.cc
+
> touch liba.cc; echo "int main() {}" > main.cc
> cmake -B build -S . -G Ninja
> ninja -C build -j1 --verbose
[1/4] /usr/bin/c++ -DDEF_PRIVATE -DDEF_PUBLIC [..] .../liba.cc
diff --git a/development/gcc.html b/development/gcc.html
index 3bd5c24..99a3117 100644
--- a/development/gcc.html
+++ b/development/gcc.html
@@ -213,7 +213,7 @@ accordingly to reduce number of jump instructions.
See on compiler explorer.
The semantics of this hint are as follows, the compiler prioritises expr == cond
. So __builtin_expect(expr, 0)
means that we expect the expr
to be 0
most of the time.
echo "
+echo "
extern void foo();
extern void bar();
void run0(int x) {
@@ -224,7 +224,7 @@ void run1(int x) {
if (__builtin_expect(x,1)) { foo(); }
else { bar(); }
}
-" | gcc -O2 -S -masm=intel -o /dev/stdout -xc -
+" | gcc -O2 -S -masm=intel -o /dev/stdout -xc -
Will generate something similar to the following.
@@ -250,7 +250,7 @@ run1:
// at startup LD_LIBRARY_PATH=/moose
// Assume /foo/libbar.so
-setenv("LD_LIBRARY_PATH", "/foo", true /* overwrite */);
+setenv("LD_LIBRARY_PATH", "/foo", true /* overwrite */);
// Will look in /moose and NOT in /foo.
-dlopen("libbar.so", RTLD_LAZY);
+dlopen("libbar.so", RTLD_LAZY);
Libraries specified in LD_PRELOAD
are loaded from left-to-right
but
diff --git a/development/make.html b/development/make.html
index 3a05525..b10075f 100644
--- a/development/make.html
+++ b/development/make.html
@@ -215,12 +215,12 @@ the recipe, make provides a set of automatic variables to work with:
Walrus operator :=
added since python 3.8.
Run unittests directly from the command line as
@@ -255,19 +255,19 @@ class MyTest(unittest.TestCase):
# file: test.py
def sum(a: int, b: int) -> int:
- """Sum a and b.
+ """Sum a and b.
>>> sum(1, 2)
3
>>> sum(10, 20)
30
- """
+ """
return a + b
Micro benchmarking.
-python -m timeit '[x.strip() for x in ["a ", " b"]]'
+python -m timeit '[x.strip() for x in ["a ", " b"]]'
diff --git a/development/symbolver.html b/development/symbolver.html
index ca84401..e771672 100644
--- a/development/symbolver.html
+++ b/development/symbolver.html
@@ -197,10 +197,10 @@ Symbol table '.dynsym' contains 342 entries:
static linking against the library.
The following dump shows that the tmp
program linked against lpthread
will
depend on the symbol version GLIBC_2.3.2
, which is the default version.
-> echo "#include <pthread.h>
+> echo "#include <pthread.h>
int main() {
return pthread_cond_wait(0,0);
- }" | gcc -o tmp -xc - -lpthread;
+ }" | gcc -o tmp -xc - -lpthread;
readelf -W --dyn-syms tmp | grep pthread_cond_wait;
Symbol table '.dynsym' contains 7 entries:
@@ -272,23 +272,23 @@ symbol multiple times but in different versions.
// ..@ -> Is the unversioned symbol.
// ..@@.. -> Is the default symbol.
-__asm__(".symver func_v0,func@");
-__asm__(".symver func_v1,func@LIB_V1");
-__asm__(".symver func_v2,func@@LIB_V2");
+__asm__(".symver func_v0,func@");
+__asm__(".symver func_v1,func@LIB_V1");
+__asm__(".symver func_v2,func@@LIB_V2");
-extern "C" {
- void func_v0() { puts("func_v0"); }
- void func_v1() { puts("func_v1"); }
- void func_v2() { puts("func_v2"); }
+extern "C" {
+ void func_v0() { puts("func_v0"); }
+ void func_v1() { puts("func_v1"); }
+ void func_v2() { puts("func_v2"); }
}
-__asm__(".symver _Z11func_cpp_v1i,_Z8func_cppi@LIB_V1");
-__asm__(".symver _Z11func_cpp_v2i,_Z8func_cppi@@LIB_V2");
+__asm__(".symver _Z11func_cpp_v1i,_Z8func_cppi@LIB_V1");
+__asm__(".symver _Z11func_cpp_v2i,_Z8func_cppi@@LIB_V2");
-void func_cpp_v1(int) { puts("func_cpp_v1"); }
-void func_cpp_v2(int) { puts("func_cpp_v2"); }
+void func_cpp_v1(int) { puts("func_cpp_v1"); }
+void func_cpp_v2(int) { puts("func_cpp_v2"); }
-void func_cpp(int) { puts("func_cpp_v2"); }
+void func_cpp(int) { puts("func_cpp_v2"); }
Version script for libfoo
which defines which symbols for which versions are
exported from the ELF file.
@@ -296,8 +296,8 @@ exported from the ELF file.
LIB_V1 {
global:
func;
- extern "C++" {
- "func_cpp(int)";
+ extern "C++" {
+ "func_cpp(int)";
};
local:
*;
@@ -306,8 +306,8 @@ LIB_V1 {
LIB_V2 {
global:
func;
- extern "C++" {
- "func_cpp(int)";
+ extern "C++" {
+ "func_cpp(int)";
};
} LIB_V1;
@@ -339,7 +339,7 @@ Symbol table '.dynsym' contains 14 entries:
#include <assert.h>
// Links against default symbol in the lib.so.
-extern "C" void func();
+extern "C" void func();
int main() {
// Call the default version.
@@ -349,10 +349,10 @@ int main() {
typedef void (*fnptr)();
// Unversioned lookup.
- fnptr fn_v0 = (fnptr)dlsym(RTLD_DEFAULT, "func");
+ fnptr fn_v0 = (fnptr)dlsym(RTLD_DEFAULT, "func");
// Version lookup.
- fnptr fn_v1 = (fnptr)dlvsym(RTLD_DEFAULT, "func", "LIB_V1");
- fnptr fn_v2 = (fnptr)dlvsym(RTLD_DEFAULT, "func", "LIB_V2");
+ fnptr fn_v1 = (fnptr)dlvsym(RTLD_DEFAULT, "func", "LIB_V1");
+ fnptr fn_v2 = (fnptr)dlvsym(RTLD_DEFAULT, "func", "LIB_V2");
assert(fn_v0 != 0);
assert(fn_v1 != 0);
--
cgit v1.2.3