diff options
author | johannst <johannst@users.noreply.github.com> | 2024-02-15 23:29:57 +0000 |
---|---|---|
committer | johannst <johannst@users.noreply.github.com> | 2024-02-15 23:29:57 +0000 |
commit | bac8a5d2822835cf47175d1162030653fadd5c09 (patch) | |
tree | 28f312a114cf95ac799daac2a2caec4b8612d84d /development | |
parent | bfc5ce4bc01e5eb28969eefcc01ecfefa2601fdf (diff) | |
download | notes-bac8a5d2822835cf47175d1162030653fadd5c09.tar.gz notes-bac8a5d2822835cf47175d1162030653fadd5c09.zip |
deploy: 4485708c972815bbb6df7f5a228683aa855d553d
Diffstat (limited to 'development')
-rw-r--r-- | development/c++.html | 82 | ||||
-rw-r--r-- | development/cmake.html | 2 | ||||
-rw-r--r-- | development/gcc.html | 6 | ||||
-rw-r--r-- | development/gcov.html | 8 | ||||
-rw-r--r-- | development/ld.so.html | 4 | ||||
-rw-r--r-- | development/make.html | 12 | ||||
-rw-r--r-- | development/pgo.html | 6 | ||||
-rw-r--r-- | development/python.html | 24 | ||||
-rw-r--r-- | development/symbolver.html | 44 |
9 files changed, 94 insertions, 94 deletions
diff --git a/development/c++.html b/development/c++.html index c33016b..0d95860 100644 --- a/development/c++.html +++ b/development/c++.html @@ -326,7 +326,7 @@ int* P = reinterpret_cast<int*>(C); // Cast is ok, not yet UB. </li> <li> <p>On <code>gcc</code> strict aliasing is enabled starting with <code>-O2</code>.</p> -<pre><code class="language-bash">for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done +<pre><code class="language-bash">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 <a href="https://godbolt.org/z/e8x1af3Mh"> // 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'); } </code></pre> <h2 id="forwarding-reference-fwd-ref"><a class="header" href="#forwarding-reference-fwd-ref">Forwarding reference (<a href="https://en.cppreference.com/w/cpp/language/reference#Forwarding_references">fwd ref</a>)</a></h2> @@ -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>, ""); </code></pre> <h2 id="example-sfinae-enable_if"><a class="header" href="#example-sfinae-enable_if">Example: <a href="https://en.cppreference.com/w/cpp/language/sfinae">SFINAE</a> (<a href="https://en.cppreference.com/w/cpp/types/enable_if">enable_if</a>)</a></h2> <p>Provide a single entry point <code>Invoke</code> to call some <code>Operations</code>. @@ -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>>, ""); } </code></pre> <p>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) </code></pre> -<pre><code class="language-sh">> touch liba.cc; echo "int main() {}" > main.cc +<pre><code class="language-sh">> 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 <a href="https://godbolt.org/z/MbTHAP">compiler explorer</a>.</p> <p>The semantics of this hint are as follows, the compiler prioritises <code>expr == cond</code>. So <code>__builtin_expect(expr, 0)</code> means that we expect the <code>expr</code> to be <code>0</code> most of the time.</p> -<pre><code class="language-bash">echo " +<pre><code class="language-bash">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 - </code></pre> <p>Will generate something similar to the following.</p> <ul> @@ -250,7 +250,7 @@ run1: </code></pre> <h2 id="abi-linux"><a class="header" href="#abi-linux">ABI (Linux)</a></h2> <ul> -<li>C ABI - <a href="https://www.uclibc.org/docs/psABI-x86_64.pdf">SystemV ABI</a></li> +<li>C ABI (x86_64) - <a href="https://gitlab.com/x86-psABIs/x86-64-ABI">SystemV ABI</a></li> <li>C++ ABI - <a href="https://itanium-cxx-abi.github.io/cxx-abi">C++ Itanium ABI</a></li> </ul> diff --git a/development/gcov.html b/development/gcov.html index 49e37bd..1b7742e 100644 --- a/development/gcov.html +++ b/development/gcov.html @@ -203,9 +203,9 @@ generated for a single file for example such as</p> void tell_me(int desc) { if (desc & 1) { - std::puts("this"); + std::puts("this"); } else { - std::puts("that"); + std::puts("that"); } } @@ -251,9 +251,9 @@ clean: -: 4: 2: 5:void tell_me(int desc) { 2: 6: if (desc & 1) { - 2: 7: std::puts("this"); + 2: 7: std::puts("this"); -: 8: } else { - #####: 9: std::puts("that"); + #####: 9: std::puts("that"); -: 10: } 2: 11:} -: 12: diff --git a/development/ld.so.html b/development/ld.so.html index 952b13e..253cec4 100644 --- a/development/ld.so.html +++ b/development/ld.so.html @@ -194,10 +194,10 @@ Therefore the following is a code smell:</p> <pre><code class="language-c">// 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); </code></pre> <h2 id="ld_preload-initialization-order-and-link-map"><a class="header" href="#ld_preload-initialization-order-and-link-map">LD_PRELOAD: Initialization Order and Link Map</a></h2> <p>Libraries specified in <code>LD_PRELOAD</code> are loaded from <code>left-to-right</code> 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:</p> all: foobar blabla foo% bla%: aaa bbb bbb - @echo "@ = $@" - @echo "< = $<" - @echo "^ = $^" - @echo "+ = $+" - @echo "* = $*" - @echo "----" + @echo "@ = $@" + @echo "< = $<" + @echo "^ = $^" + @echo "+ = $+" + @echo "* = $*" + @echo "----" aaa: bbb: diff --git a/development/pgo.html b/development/pgo.html index fff9eb8..7a1a625 100644 --- a/development/pgo.html +++ b/development/pgo.html @@ -189,8 +189,8 @@ workload.</p> #define NOINLINE __attribute__((noinline)) -NOINLINE void foo() { puts("foo()"); } -NOINLINE void bar() { puts("bar()"); } +NOINLINE void foo() { puts("foo()"); } +NOINLINE void bar() { puts("bar()"); } int main(int argc, char *argv[]) { if (argc == 2) { @@ -231,7 +231,7 @@ clang -o test test.cc -O3 -fprofile-instr-generate # Collect profiling data from multiple runs. for i in {0..10}; do - LLVM_PROFILE_FILE="prof.clang/%p.profraw" ./test $(seq 0 $i) + LLVM_PROFILE_FILE="prof.clang/%p.profraw" ./test $(seq 0 $i) done # Merge raw profiling data into single profile data. diff --git a/development/python.html b/development/python.html index 5d15d0d..4aa6ff9 100644 --- a/development/python.html +++ b/development/python.html @@ -183,26 +183,26 @@ def log(f: Callable[[int], None]) -> Callable[[int], None]: def inner(x: int): - print(f"log::inner f={f.__name__} x={x}") + print(f"log::inner f={f.__name__} x={x}") f(x) return inner @log def some_fn(x: int): - print(f"some_fn x={x}") + print(f"some_fn x={x}") def log_tag(tag: str) -> Callable[[Callable[[int], None]], Callable[[int], None]]: def decorator(f: Callable[[int], None]) -> Callable[[int], None]: def inner(x: int): - print(f"log_tag::inner f={f.__name__} tag={tag} x={x}") + print(f"log_tag::inner f={f.__name__} tag={tag} x={x}") f(x) return inner return decorator -@log_tag("some_tag") +@log_tag("some_tag") def some_fn2(x: int): - print(f"some_fn2 x={x}") + print(f"some_fn2 x={x}") </code></pre> <h2 id="walrus-operator-run"><a class="header" href="#walrus-operator-run">Walrus operator [<a href="https://www.online-python.com/9T12PvmKVy">run</a>]</a></h2> <p>Walrus operator <code>:=</code> added since <strong>python 3.8</strong>.</p> @@ -214,20 +214,20 @@ def foo(ret: Optional[int]) -> Optional[int]: return ret if r := foo(None): - print(f"foo(None) -> {r}") + print(f"foo(None) -> {r}") if r := foo(1337): - print(f"foo(1337) -> {r}") + print(f"foo(1337) -> {r}") # Example 2: while let statements toks = iter(['a', 'b', 'c']) while tok := next(toks, None): - print(f"{tok}") + print(f"{tok}") # Example 3: list comprehension -print([tok for t in [" a", " ", " b "] if (tok := t.strip())]) +print([tok for t in [" a", " ", " b "] if (tok := t.strip())]) </code></pre> <h2 id="unittest-run"><a class="header" href="#unittest-run"><a href="https://docs.python.org/3/library/unittest.html">Unittest</a> [<a href="https://www.online-python.com/2fit4UcbzI">run</a>]</a></h2> <p>Run unittests directly from the command line as <br /> @@ -255,19 +255,19 @@ class MyTest(unittest.TestCase): <pre><code class="language-python"># 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 </code></pre> <h2 id="timeit"><a class="header" href="#timeit"><a href="https://docs.python.org/3/library/timeit.html">timeit</a></a></h2> <p>Micro benchmarking.</p> -<pre><code class="language-bash">python -m timeit '[x.strip() for x in ["a ", " b"]]' +<pre><code class="language-bash">python -m timeit '[x.strip() for x in ["a ", " b"]]' </code></pre> </main> 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 <code>tmp</code> program linked against <code>lpthread</code> will depend on the symbol version <code>GLIBC_2.3.2</code>, which is the default version.</p> -<pre><code class="language-bash">> echo "#include <pthread.h> +<pre><code class="language-bash">> 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.</p> // ..@ -> 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"); } </code></pre> <p>Version script for <code>libfoo</code> which defines which symbols for which versions are exported from the ELF file.</p> @@ -296,8 +296,8 @@ exported from the ELF file.</p> 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; </code></pre> @@ -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); |