From eaad036407c9546be0de27f61745fef4b6856e56 Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 29 May 2023 20:34:16 +0000 Subject: deploy: d2013ee5952bbcf88906a832748783e372f3a939 --- development/c++.html | 169 +++++++++++++++++++++++- development/c++/.clang-format | 2 +- development/c++/Makefile | 2 +- development/c++/fwd-perfect.cc | 82 ++++++++++++ development/c++/fwd.cc | 58 +++++++++ development/c++/meta2.cc | 12 +- development/c++/meta4.cc | 4 +- development/c++filt.html | 2 +- development/gcc.html | 13 +- development/gcov.html | 288 +++++++++++++++++++++++++++++++++++++++++ development/gcov/Makefile | 24 ++++ development/gcov/cov.cc | 17 +++ development/glibc.html | 2 +- development/index.html | 3 +- development/ld.so.html | 2 +- development/make.html | 17 ++- development/python.html | 6 +- development/symbolver.html | 2 +- 18 files changed, 683 insertions(+), 22 deletions(-) create mode 100644 development/c++/fwd-perfect.cc create mode 100644 development/c++/fwd.cc create mode 100644 development/gcov.html create mode 100644 development/gcov/Makefile create mode 100644 development/gcov/cov.cc (limited to 'development') diff --git a/development/c++.html b/development/c++.html index 811aa7d..4ed1fad 100644 --- a/development/c++.html +++ b/development/c++.html @@ -83,7 +83,7 @@ @@ -148,6 +148,7 @@

c++

+

Source files of most examples is available here.

Type deduction

Force compile error to see what auto is deduced to.

auto foo = bar();
@@ -193,6 +194,74 @@ int main() {
     show(1, 1.0, "foo", 'a');
 }
 
+

Forwarding reference (fwd ref)

+

A forwarding reference is a special references that preserves the value category of a function parameter and therefore allows for perfect +forwarding.

+

A forwarding reference is a parameter of a function template, which is declared +as rvalue reference to a non-cv qualified type template parameter.

+
template<typename T>
+void fn(T&& param); // param is a forwarding reference
+
+

Perfect forwarding can be achieved with std::forward. This for +example allows a wrapper function to pass a parameter with the exact same +value category to a down-stream function which is being invoked in the wrapper.

+
#include <cstdio>
+#include <utility>
+
+struct M {};
+
+// -- CONSUMER -----------------------------------------------------------------
+
+void use(M&) {
+    puts(__PRETTY_FUNCTION__);
+}
+
+void use(M&&) {
+    puts(__PRETTY_FUNCTION__);
+}
+
+// -- TESTER -------------------------------------------------------------------
+
+template<typename T>
+void wrapper(T&& param) {  // forwarding reference
+    puts(__PRETTY_FUNCTION__);
+    // PARAM is an lvalue, therefore this always calls use(M&).
+    use(param);
+}
+
+template<typename T>
+void fwd_wrapper(T&& param) {  // forwarding reference
+    puts(__PRETTY_FUNCTION__);
+    // PARAM is an lvalue, but std::forward returns PARAM with the same value
+    // category as the forwarding reference takes.
+    use(std::forward<T>(param));
+}
+
+// -- MAIN ---------------------------------------------------------------------
+
+int main() {
+    {
+        std::puts("==> wrapper rvalue reference");
+        wrapper(M{});
+        // calls use(M&).
+
+        std::puts("==> wrapper lvalue reference");
+        struct M m;
+        wrapper(m);
+        // calls use(M&).
+    }
+    {
+        std::puts("==> fwd_wrapper rvalue reference");
+        fwd_wrapper(M{});
+        // calls use(M&&).
+
+        std::puts("==> fwd_wrapper lvalue reference");
+        struct M m;
+        fwd_wrapper(m);
+        // calls use(M&).
+    }
+}
+

Example: any_of template meta function

#include <type_traits>
 
@@ -275,7 +344,9 @@ void Invoke(const Ctx& C, P... params) {
 // Custom context.
 
 struct Ctx {
-    void out(const char* s, unsigned v) const { printf("%s%x\n", s, v); }
+    void out(const char* s, unsigned v) const {
+        printf("%s%x\n", s, v);
+    }
 };
 
 // Operations to invoke.
@@ -286,7 +357,9 @@ struct OpA {
     using Return = int;
     static constexpr const char* const Name = "OpA";
 
-    constexpr Return operator()(int a, int b) const { return a + b; }
+    constexpr Return operator()(int a, int b) const {
+        return a + b;
+    }
 };
 
 template<typename Ctx>
@@ -295,7 +368,9 @@ struct OpB {
     using Return = void;
     static constexpr const char* const Name = "OpB";
 
-    Return operator()(const Ctx& C, unsigned a) const { C.out("a = ", a); }
+    Return operator()(const Ctx& C, unsigned a) const {
+        C.out("a = ", a);
+    }
 };
 
 int main() {
@@ -332,7 +407,9 @@ struct registry {
         return r.second;
     }
 
-    R invoke(const std::string& nm, P... p) const { return invoke_impl<R>(nm, p...); }
+    R invoke(const std::string& nm, P... p) const {
+        return invoke_impl<R>(nm, p...);
+    }
 
     void dump() const {
         for (const auto& it : m_fns) {
@@ -593,6 +670,88 @@ int main() {
     // * (4) <char, short> pattern does not match
     // * No specialization matches, take the primary template.
 }
+
+

Example: Perfect forwarding

+
#include <cassert>
+#include <cstdio>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+struct S {};
+
+struct M {
+    M() {
+        std::puts("M()");
+    }
+    M(const M&) {
+        std::puts("M(M&)");
+    }
+    M(M&&) {
+        std::puts("M(M&&)");
+    }
+    M& operator=(const M&) = delete;
+    M& operator=(M&&) = delete;
+
+    M(S&, int) {
+        std::puts("M(S&)");
+    }
+    M(S&&, int) {
+        std::puts("M(S&&)");
+    }
+    ~M() {
+        std::puts("~M()");
+    }
+};
+
+template<typename T>
+struct option {
+    static_assert(!std::is_reference_v<T>);
+
+    constexpr option() = default;
+
+    template<typename... Params>
+    constexpr option(Params&&... params) : m_has_val(true) {
+        // BAD: does not perfectly forward!
+        //      eg, if option(S&&) is invoked, this would invoke M(S&).
+        // new (&m_val) T(params...);
+
+        // GOOD: perfectly forwards params to constructor of T.
+        new (m_val) T(std::forward<Params>(params)...);
+    }
+
+    ~option() {
+        reset();
+    }
+
+    constexpr T& value() {
+        assert(m_has_val);
+        return *reinterpret_cast<T*>(m_val);
+    }
+
+  private:
+    constexpr void reset() {
+        if (!m_has_val) {
+            return;
+        }
+        if constexpr (!std::is_trivially_destructible_v<T>) {
+            value().~T();
+        };
+    }
+
+    alignas(T) char m_val[sizeof(T)];
+    bool m_has_val{false};
+};
+
+int main() {
+    std::puts("==> case 1");
+    // invokes M(S&&, int)
+    option<M> opt1(S{}, 123);
+
+    std::puts("==> case 2");
+    // invokes M() + M(M&&)
+    option<M> x /* option(M&&) + M(M&&) */ = M{} /* M() */;
+}
 
diff --git a/development/c++/.clang-format b/development/c++/.clang-format index 3cfb373..1b5900c 100644 --- a/development/c++/.clang-format +++ b/development/c++/.clang-format @@ -18,7 +18,7 @@ AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Inline +AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: false diff --git a/development/c++/Makefile b/development/c++/Makefile index ca752d9..622bfd3 100644 --- a/development/c++/Makefile +++ b/development/c++/Makefile @@ -1,4 +1,4 @@ -SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc +SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc fwd-perfect.cc BIN = $(SRC:.cc=) all: $(BIN) diff --git a/development/c++/fwd-perfect.cc b/development/c++/fwd-perfect.cc new file mode 100644 index 0000000..2fafc3e --- /dev/null +++ b/development/c++/fwd-perfect.cc @@ -0,0 +1,82 @@ +// Copyright (C) 2023 johannst + +#include +#include +#include +#include +#include + +struct S {}; + +struct M { + M() { + std::puts("M()"); + } + M(const M&) { + std::puts("M(M&)"); + } + M(M&&) { + std::puts("M(M&&)"); + } + M& operator=(const M&) = delete; + M& operator=(M&&) = delete; + + M(S&, int) { + std::puts("M(S&)"); + } + M(S&&, int) { + std::puts("M(S&&)"); + } + ~M() { + std::puts("~M()"); + } +}; + +template +struct option { + static_assert(!std::is_reference_v); + + constexpr option() = default; + + template + constexpr option(Params&&... params) : m_has_val(true) { + // BAD: does not perfectly forward! + // eg, if option(S&&) is invoked, this would invoke M(S&). + // new (&m_val) T(params...); + + // GOOD: perfectly forwards params to constructor of T. + new (m_val) T(std::forward(params)...); + } + + ~option() { + reset(); + } + + constexpr T& value() { + assert(m_has_val); + return *reinterpret_cast(m_val); + } + + private: + constexpr void reset() { + if (!m_has_val) { + return; + } + if constexpr (!std::is_trivially_destructible_v) { + value().~T(); + }; + } + + alignas(T) char m_val[sizeof(T)]; + bool m_has_val{false}; +}; + +int main() { + std::puts("==> case 1"); + // invokes M(S&&, int) + option opt1(S{}, 123); + + std::puts("==> case 2"); + // invokes M() + M(M&&) + option x /* option(M&&) + M(M&&) */ = M{} /* M() */; +} diff --git a/development/c++/fwd.cc b/development/c++/fwd.cc new file mode 100644 index 0000000..802d5bb --- /dev/null +++ b/development/c++/fwd.cc @@ -0,0 +1,58 @@ +// Copyright (C) 2023 johannst + +#include +#include + +struct M {}; + +// -- CONSUMER ----------------------------------------------------------------- + +void use(M&) { + puts(__PRETTY_FUNCTION__); +} + +void use(M&&) { + puts(__PRETTY_FUNCTION__); +} + +// -- TESTER ------------------------------------------------------------------- + +template +void wrapper(T&& param) { // forwarding reference + puts(__PRETTY_FUNCTION__); + // PARAM is an lvalue, therefore this always calls use(M&). + use(param); +} + +template +void fwd_wrapper(T&& param) { // forwarding reference + puts(__PRETTY_FUNCTION__); + // PARAM is an lvalue, but std::forward returns PARAM with the same value + // category as the forwarding reference takes. + use(std::forward(param)); +} + +// -- MAIN --------------------------------------------------------------------- + +int main() { + { + std::puts("==> wrapper rvalue reference"); + wrapper(M{}); + // calls use(M&). + + std::puts("==> wrapper lvalue reference"); + struct M m; + wrapper(m); + // calls use(M&). + } + { + std::puts("==> fwd_wrapper rvalue reference"); + fwd_wrapper(M{}); + // calls use(M&&). + + std::puts("==> fwd_wrapper lvalue reference"); + struct M m; + fwd_wrapper(m); + // calls use(M&). + } +} diff --git a/development/c++/meta2.cc b/development/c++/meta2.cc index 4c1194f..cd9c625 100644 --- a/development/c++/meta2.cc +++ b/development/c++/meta2.cc @@ -52,7 +52,9 @@ void Invoke(const Ctx& C, P... params) { // Custom context. struct Ctx { - void out(const char* s, unsigned v) const { printf("%s%x\n", s, v); } + void out(const char* s, unsigned v) const { + printf("%s%x\n", s, v); + } }; // Operations to invoke. @@ -63,7 +65,9 @@ struct OpA { using Return = int; static constexpr const char* const Name = "OpA"; - constexpr Return operator()(int a, int b) const { return a + b; } + constexpr Return operator()(int a, int b) const { + return a + b; + } }; template @@ -72,7 +76,9 @@ struct OpB { using Return = void; static constexpr const char* const Name = "OpB"; - Return operator()(const Ctx& C, unsigned a) const { C.out("a = ", a); } + Return operator()(const Ctx& C, unsigned a) const { + C.out("a = ", a); + } }; int main() { diff --git a/development/c++/meta4.cc b/development/c++/meta4.cc index 9c3be77..7437cb4 100644 --- a/development/c++/meta4.cc +++ b/development/c++/meta4.cc @@ -22,7 +22,9 @@ struct registry { return r.second; } - R invoke(const std::string& nm, P... p) const { return invoke_impl(nm, p...); } + R invoke(const std::string& nm, P... p) const { + return invoke_impl(nm, p...); + } void dump() const { for (const auto& it : m_fns) { diff --git a/development/c++filt.html b/development/c++filt.html index c9c486f..9b9a37a 100644 --- a/development/c++filt.html +++ b/development/c++filt.html @@ -83,7 +83,7 @@ diff --git a/development/gcc.html b/development/gcc.html index 170c5e0..bb2e845 100644 --- a/development/gcc.html +++ b/development/gcc.html @@ -83,7 +83,7 @@ @@ -158,6 +158,8 @@
  • -dM list only #define statements
  • -### dry-run, outputting exact compiler/linker invocations
  • -print-multi-lib print available multilib configurations
  • +
  • --help=<class> print description of cmdline options for given class, eg +warnings, optimizers, target, c, c++
  • Target options

    # List all target options with their description.
    @@ -166,6 +168,15 @@ gcc --help=target
     # Configure for current cpu arch and query (-Q) value of options.
     gcc -march=native -Q --help=target
     
    +

    Warnings / optimizations

    +
    # List available warnings with short description.
    +gcc --help=warnings
    +# List available optimizations with short description.
    +gcc --help=optimizers
    +
    +# Prepend --help with `-Q` to print wheter options are enabled or disabled
    +# instead showing their description.
    +

    Builtins

    __builtin_expect(expr, cond)

    Give the compiler a hint which branch is hot, so it can lay out the code diff --git a/development/gcov.html b/development/gcov.html new file mode 100644 index 0000000..582e703 --- /dev/null +++ b/development/gcov.html @@ -0,0 +1,288 @@ + + + + + + gcov - Notes + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    gcov(1)

    +

    Generate code coverage reports in text format.

    +

    Compile the source files of interest and link the final binary with the +following flags:

    +
      +
    • -fprofile-arcs instruments the generated code such that it writes a .gcda +file when being executed with details about which branches are taken
    • +
    • -ftest-coverage writes a .gcno notes file which is used by gcov during +generation of the coverage report
    • +
    +

    Depending on the build environment one may also set -fprofile-abs-path to +generate absolute path names into the .gcno note files, this can ease setups +where compilations are done in different directories to the source directory.

    +
    +

    gcc / clang also support an alias flag --coverage which during +compilation time is equivalent to -fprofile-arcs -ftest-coverage and during +link time -lgcov.

    +
    +

    After running the instrumented binary, the human readable report can then be +generated for a single file for example such as

    +
    gcov <SRC FILE | OBJ FILE>
    +
    +

    Example

    +
    #include <cstdio>
    +
    +void tell_me(int desc) {
    +  if (desc & 1) {
    +    std::puts("this");
    +  } else {
    +    std::puts("that");
    +  }
    +}
    +
    +int main(int argc, char *argv[]) {
    +  tell_me(argc);
    +  tell_me(argc);
    +  return 0;
    +}
    +
    +

    The gcov coverage report can be generated as follows for gcc or clang.

    +
    CXXFLAGS = -fprofile-arcs -ftest-coverage
    +# or the alias
    +#CXXFLAGS = --coverage
    +
    +cov-gcc: clean
    +	g++ $(CXXFLAGS) -c -o cov.o cov.cc
    +	g++ $(CXXFLAGS) -o $@ cov.o
    +	./$@
    +	gcov --demangled-names cov.cc
    +	cat cov.cc.gcov
    +.PHONY: cov-gcc
    +
    +cov-clang: clean
    +	clang++ $(CXXFLAGS) -c -o cov.o cov.cc
    +	clang++ $(CXXFLAGS) -o $@ cov.o
    +	./$@
    +	llvm-cov gcov --demangled-names cov.cc
    +	cat cov.cc.gcov
    +.PHONY: cov-clang
    +
    +clean:
    +	$(RM) *.gcov *.gcno *.gcda *.o cov-*
    +
    +

    The will generate a report similar to the following.

    +
    cat cov.cc.gcov
    +        -:    0:Source:cov.cc
    +        -:    0:Graph:cov.gcno
    +        -:    0:Data:cov.gcda
    +        -:    0:Runs:1
    +        -:    1:// Copyright (C) 2023 johannst
    +        -:    2:
    +        -:    3:#include <cstdio>
    +        -:    4:
    +        2:    5:void tell_me(int desc) {
    +        2:    6:  if (desc & 1) {
    +        2:    7:    std::puts("this");
    +        -:    8:  } else {
    +    #####:    9:    std::puts("that");
    +        -:   10:  }
    +        2:   11:}
    +        -:   12:
    +        1:   13:int main(int argc, char *argv[]) {
    +        1:   14:  tell_me(argc);
    +        1:   15:  tell_me(argc);
    +        1:   16:  return 0;
    +        -:   17:}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/development/gcov/Makefile b/development/gcov/Makefile new file mode 100644 index 0000000..f27f8d8 --- /dev/null +++ b/development/gcov/Makefile @@ -0,0 +1,24 @@ +# Copyright (C) 2023 johannst + +CXXFLAGS = -fprofile-arcs -ftest-coverage +# or the alias +#CXXFLAGS = --coverage + +cov-gcc: clean + g++ $(CXXFLAGS) -c -o cov.o cov.cc + g++ $(CXXFLAGS) -o $@ cov.o + ./$@ + gcov --demangled-names cov.cc + cat cov.cc.gcov +.PHONY: cov-gcc + +cov-clang: clean + clang++ $(CXXFLAGS) -c -o cov.o cov.cc + clang++ $(CXXFLAGS) -o $@ cov.o + ./$@ + llvm-cov gcov --demangled-names cov.cc + cat cov.cc.gcov +.PHONY: cov-clang + +clean: + $(RM) *.gcov *.gcno *.gcda *.o cov-* diff --git a/development/gcov/cov.cc b/development/gcov/cov.cc new file mode 100644 index 0000000..3737d81 --- /dev/null +++ b/development/gcov/cov.cc @@ -0,0 +1,17 @@ +// Copyright (C) 2023 johannst + +#include + +void tell_me(int desc) { + if (desc & 1) { + std::puts("this"); + } else { + std::puts("that"); + } +} + +int main(int argc, char *argv[]) { + tell_me(argc); + tell_me(argc); + return 0; +} diff --git a/development/glibc.html b/development/glibc.html index 7f0f10b..ab9c252 100644 --- a/development/glibc.html +++ b/development/glibc.html @@ -83,7 +83,7 @@ diff --git a/development/index.html b/development/index.html index 8b220d5..f6e4874 100644 --- a/development/index.html +++ b/development/index.html @@ -83,7 +83,7 @@ @@ -157,6 +157,7 @@
  • ld.so
  • symbol versioning
  • python
  • +
  • gcov
  • diff --git a/development/ld.so.html b/development/ld.so.html index afe0dee..5a8326e 100644 --- a/development/ld.so.html +++ b/development/ld.so.html @@ -83,7 +83,7 @@ diff --git a/development/make.html b/development/make.html index bb004a2..fe08ad1 100644 --- a/development/make.html +++ b/development/make.html @@ -83,7 +83,7 @@ @@ -197,7 +197,7 @@ aaa: bbb:

    Running above Makefile gives:

    -
    @ = foobar
    +
    @ = foobar
     < = aaa
     ^ = aaa bbb
     + = aaa bbb bbb
    @@ -214,6 +214,19 @@ bbb:
     
    • $(CURDIR): Path of current working dir after using make -C path
    +

    Arguments

    +

    Arguments specified on the command line override ordinary variable +assignments in the makefile (overriding variables).

    +
    VAR = abc
    +all:
    +	@echo VAR=$(VAR)
    +
    +
    # make
    +VAR=abc
    +
    +# make VAR=123
    +VAR=123
    +

    Useful functions

    Substitution references

    Substitute strings matching pattern in a list.

    diff --git a/development/python.html b/development/python.html index 8b0c3ce..c847ad5 100644 --- a/development/python.html +++ b/development/python.html @@ -83,7 +83,7 @@ @@ -249,7 +249,7 @@ def sum(a: int, b: int) -> int: - @@ -263,7 +263,7 @@ def sum(a: int, b: int) -> int: - diff --git a/development/symbolver.html b/development/symbolver.html index 3fa715a..d43b7d0 100644 --- a/development/symbolver.html +++ b/development/symbolver.html @@ -83,7 +83,7 @@ -- cgit v1.2.3