centralized performance resources
This commit is contained in:
commit
50b15a1522
63 changed files with 328466 additions and 0 deletions
5
perf-cpp/analysis-and-tuning.md
Normal file
5
perf-cpp/analysis-and-tuning.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# performance
|
||||
|
||||
## [profiling - algorithmica](https://en.algorithmica.org/hpc/profiling/)
|
||||
|
||||
## [performance analysis and tuning](https://en.algorithmica.org/hpc/profiling/)
|
||||
816
perf-cpp/cpp.md
Normal file
816
perf-cpp/cpp.md
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
# CPP
|
||||
|
||||
## [learncpp](https://www.learncpp.com/)
|
||||
|
||||
- compilation process: preprocess -> compilation -> assembly -> linking
|
||||
- lexing for grammar validity -> ast type checking
|
||||
- files are compiled top to bottom, & individually (must include libraries
|
||||
multiple times)
|
||||
|
||||
- e.g. below, type checker evaluates, sees f returns `void` -> pairs with
|
||||
`std::cout` operator `<<` -> this is invalid -> *compile-time* caught
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
void printA()
|
||||
{
|
||||
std::cout << "A\n";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << printA() << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- initialization
|
||||
- why list initialization -> narrowing conversions disallowed
|
||||
|
||||
- [operator precendece](https://en.cppreference.com/w/cpp/language/operator_precedence.html)
|
||||
|
||||
- nested functions disallowed
|
||||
- many features of cpp don't nec. have rhyme or reason; it is a language
|
||||
[with history](https://www.reddit.com/r/cpp/comments/199ho2b/why_doesnt_standard_c_support_nested_functions/) for good or bad
|
||||
|
||||
- cpp compiles sequentially (i.e. top to bottom)
|
||||
- <u>One Definition Rule</u>: per file, per scope, one definition only; per
|
||||
program too; types/templates/inline functions can have other definitions
|
||||
- ? why are header files usually omitted in c++ compilation processes?
|
||||
- ? why does the cpp - include header structure in projects work, espec. wrt
|
||||
ODR?
|
||||
- NOTE: *compiling* does not need impls (just needs ) -> *linking* does
|
||||
- NOTE: research about linking later, but just know linking has a symbol
|
||||
table to map symbols to literaly code locations
|
||||
|
||||
### namespaces
|
||||
|
||||
- *simple* -> wrap simple name
|
||||
- "name mangling" includes the namespace prefix in compilation -> easy to
|
||||
identify
|
||||
|
||||
|
||||
## preprocessing
|
||||
|
||||
- when is it done?
|
||||
- for each cpp file, copy-paste in the includes & compile into translation
|
||||
units separately
|
||||
- what's the output of pre-processsed files called?
|
||||
|
||||
- Lesson: use macros sparingly besides eliminating code compilation (i.e. in
|
||||
libraries) and compilation-specific processes
|
||||
|
||||
- `""` vs. `<>` in includes: look locally relative to the path, then
|
||||
system/*only* look in the system
|
||||
|
||||
- Why not use relative includes (~~configure the compile-time include path instead~~)
|
||||
- Why even use header guards? What's the common pattern that necessitates them?
|
||||
- 1 file including 2 files that each include another file -> duplicate
|
||||
definition
|
||||
- ? why do header guards resolve this problem? ~~because each translation unit
|
||||
is treated separately by the pre-processor. files are compiled separately but
|
||||
a file compiling joint ones doesn't duplicate includes via the guard.~~
|
||||
- long story short, every file must have one of all each included file ->
|
||||
prevent ODR violations
|
||||
- ? why don't define methods in header files? ~~multiple cpp can include
|
||||
headers, leading to ODR violations~~
|
||||
- only have ONE function implementation in source files -> compilation
|
||||
resolves with declarations & implementations linked easily
|
||||
|
||||
## type conversion
|
||||
|
||||
- <u>implicit conversions</u> convert types when acceptable
|
||||
- pre-defined set of compiler rules
|
||||
- why is using const in value parameters useless?
|
||||
|
||||
## optimization
|
||||
|
||||
- what's the official rule for how c++ compilres can change code? ~~when the
|
||||
"observable behavior" is identical - i.e. cahnge anything if output is the
|
||||
same~~
|
||||
- methods:
|
||||
1. constant folding
|
||||
2. dead code elimination
|
||||
|
||||
## constants
|
||||
|
||||
- "by default, expressions are evaluated at \_"?
|
||||
- it's up to the *compiler* as to whether *anything* is evaluated at compile
|
||||
time
|
||||
- <u>constexpr</u>: declares value as a compile-time available constant - all args *must* be
|
||||
evaluatable at compile time (i.e. be constant expressoions) - BUT... this is optional!
|
||||
- values must be KNOWN -> not nec. imply compilation
|
||||
- "constexprness" implies constness
|
||||
- `std::string_view` is a fragile container
|
||||
|
||||
## [order of operations](https://en.cppreference.com/w/cpp/language/operator_precedence.html)
|
||||
|
||||
- why is this bad? ~~according to c++ spec, order of function evaluation is not
|
||||
specified - generally speaking, args should not have side effects~~
|
||||
|
||||
```cpp
|
||||
auto x = 5;
|
||||
|
||||
f(x++, ++x);
|
||||
```
|
||||
|
||||
- what does this return, and why? what does it teach us abou tthe ternary
|
||||
operations?
|
||||
- ~~due to operator precedence, 0 is first printed; then the returned
|
||||
std::cout& is implicitly cast to a boolean and the result of the terary is
|
||||
discarded~~
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
int x { 2 };
|
||||
std::cout << (x < 0) ? "negative" : "non-negative";
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- NOTE: `<=>`, bitwise operators, and more have lower priority than `<<`
|
||||
|
||||
- I allocate N bits into a `std::bitset`. How many bits of memory are allocated
|
||||
and why?
|
||||
~~ceil(N / bits per machine word) * number bits per word (rounded up) -
|
||||
bitsets are fixed size, contiguous arrays of machine words for convenient
|
||||
accessing~~
|
||||
|
||||
## scopes
|
||||
|
||||
- explain lifetime management in c++
|
||||
- an identifier can have multiple scopes - T/F
|
||||
- how does the compiler search for scope resolution?
|
||||
||it works from the inside out resolving symbols||
|
||||
|
||||
- how can i refer to x in the outer example? ||use the scope resolution
|
||||
operator: `f::x`||
|
||||
|
||||
```cpp
|
||||
void f() {
|
||||
int x;
|
||||
{
|
||||
int x;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## linkage
|
||||
|
||||
- what is linkage? ||linkage determines visibility & to the linker||
|
||||
- can the linker see variables with internal linkage? ||intuitively no - they'll
|
||||
never need to be linked because they are not accessible from other translation
|
||||
units||
|
||||
- functions default to {external, internal} linkage ||external||
|
||||
- non-constant global variables? ||external||
|
||||
- how to declare constant global to have external linkage? ||add the [storage class specifier](https://en.cppreference.com/w/cpp/language/storage_duration.html) `extern`||
|
||||
- why can `extern` variables not be `constexpr`? ||value must be evaluatable at
|
||||
compile-time - if another file sets the value, the compiler isn't
|
||||
sophisticated to know (it compiles files in isolation)||
|
||||
|
||||
- What’s the difference between a variable’s scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have?
|
||||
- ||scope -> where defined/accessible in the code; duration ->
|
||||
creation/destruction bounds (can be different in more complex areas? give an
|
||||
example), linkage -> visibility beyond translation unit||
|
||||
|
||||
## [inlining](https://en.cppreference.com/w/cpp/language/inline.html)
|
||||
|
||||
- centrally concerned with *linkage*
|
||||
- external linkage can cause ODR violations -> resolve with `inline`
|
||||
- when to not inline? ||size of the inlined function outweighs the overhead of
|
||||
inlining itself||
|
||||
- why can you not force the compiler to inline?
|
||||
- why is `inline` not to be used for inlining?
|
||||
- ||inlining is a per-function call concept, but the keyword makes it apply to
|
||||
all scenarios||
|
||||
|
||||
- `inline` is about removing ODR violations across *multiple* different files.
|
||||
- how does this vary from header guards?
|
||||
- when should you use inline?
|
||||
- `inline` really means ||multiple definitions are permitted|| instead of inline the call
|
||||
|
||||
- NOTE: this still honestly doesn't make much sense to me
|
||||
- Review linkage, compilation process, ODR, and inlining
|
||||
|
||||
- We usually just want ONE definition - so we keep implementations in ||source||
|
||||
files so that on compilation the ||linker|| can easily find the function
|
||||
definition (which it can do because it has ||external|| linkage by default)
|
||||
- When defining something like a function ||implementation|| in a ||header||
|
||||
file, this pattern is broken. why? ||multiple function impls with external
|
||||
linkage will exist||
|
||||
- inline then allows separate ||translation units||, indeed compiled separately, to resolve the symbol fine
|
||||
|
||||
- marking something as `inline` does/does not ||does not|| change the storage class specifier. the linker ||merges|| multiple definitions of variables marked inline
|
||||
- `inline` variables have ||external|| linkage by default - why? ||duh - so
|
||||
linker can resolve between TUs||
|
||||
|
||||
## static
|
||||
|
||||
- has so many different meaning
|
||||
|
||||
- What does `static` refer to inside/outside a function? ||static *storage
|
||||
duration*/*internal linkage*||
|
||||
variable to start/end at the time of the program
|
||||
|
||||
- how do I give a function internal linkage? ||mark as `static`||
|
||||
|
||||
## scoping and brackets
|
||||
|
||||
- which does the else bind to? ||closest/nearest unmatched if -> the if (y)
|
||||
block||
|
||||
|
||||
- explain loops without brackets in terms of grammar
|
||||
- ||basically, grammatically an if/for/etc. cover ones statement. an enclosing body with brackets is a <u>compound statement</u>. no
|
||||
brackets -> the first statement in the tree is grabbed||
|
||||
- why does this then work with chained elses and else ifs? note that else ifs are
|
||||
parsed as ifs inside of else blocks
|
||||
```cpp
|
||||
if (x)
|
||||
if (y)
|
||||
a();
|
||||
else
|
||||
b();
|
||||
```
|
||||
|
||||
|
||||
## switch statements
|
||||
|
||||
- compilers are smart, and may do the following for switch statements:
|
||||
|
||||
1. direct access jump tables
|
||||
2. binary search when too big
|
||||
3. re-indexing (i.e. values start at large n)
|
||||
|
||||
## loops
|
||||
|
||||
- mostly get compiled to the same thing
|
||||
|
||||
## function overloading implicit type conversion
|
||||
|
||||
- why is it needed? ||internal representation of different types differs||
|
||||
|
||||
- `using` keyword does a variety of things
|
||||
- what happens when multiple function candidates are available?
|
||||
- overload resolution -> choose ONE best candidate (if multiple, error)
|
||||
|
||||
- What's the output (and why?)
|
||||
- ||double because there's a promotion to float||
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
void f(int) { std::cout << "f(int)\n"; }
|
||||
void f(double) { std::cout << "f(double)\n"; }
|
||||
|
||||
int main() {
|
||||
f(3.14f);
|
||||
int x = 3.14f; // also conversion
|
||||
}
|
||||
```
|
||||
|
||||
- in <u>function overloading</u>, acc. to C++ spec resolve function choices:
|
||||
1. exact match
|
||||
2. promote *arguments*
|
||||
3. user defined conversions
|
||||
4. ellipses
|
||||
5. give up
|
||||
|
||||
- ? what's the difference between compiler vs. linker resolving functions?
|
||||
- ~~compiler resolves function calls via OVERLOADING - indeed, the compiler
|
||||
must know all function signatures. subsequently, each
|
||||
function is then mapped to in the linker phase.~~
|
||||
|
||||
- What's the output (and why?)
|
||||
- ||compilation error -> CONVERSION of the same rank||
|
||||
```cpp
|
||||
void f(long) { std::cout << "f(long)\n"; }
|
||||
void f(unsigned long) { std::cout << "f(unsigned long)\n"; }
|
||||
|
||||
int main() {
|
||||
f(3.14f);
|
||||
return 0;
|
||||
```
|
||||
|
||||
- NOTE: conversion is complex
|
||||
- promotion -> special, correct promotion -> prioritized (prioritized first)
|
||||
- only includes small types, not like `long`
|
||||
- conversion -> otherwise
|
||||
- compilers do the five following conversions, and in which order?
|
||||
|
||||
||
|
||||
1. exact (including qualifiers such as cv, array-to-pointer, etc.)
|
||||
2. promotion
|
||||
3. conversion (and any path, promotion + conversion, etc)
|
||||
4. user-defined
|
||||
5. variadic (i.e. smash into an ellipses)
|
||||
||
|
||||
|
||||
- valid or not, and why?
|
||||
- ||invalid - return types not used in function overloading for a)
|
||||
compatibility reasons with C and b) trouble distinguishing between desired
|
||||
return type (how can you indicate which function you want when there isn't
|
||||
always a straightforward way to do such?). e.g. `auto X = x(); f(());`,
|
||||
etc. Generally, it's convenient to just look at call context & know return
|
||||
value after deducing the right function call.||
|
||||
- || in other words, a function's type signature is everything but the
|
||||
return type.||
|
||||
|
||||
```cpp
|
||||
int x();
|
||||
double x();
|
||||
```
|
||||
|
||||
- exactly what does this do?
|
||||
- || *halt* compilation if the function is called. code is still compiled,
|
||||
but `delete` forbids the call||
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
void printInt(T x) = delete;
|
||||
```
|
||||
|
||||
### default arguments
|
||||
|
||||
- are default args part of function signature ||no||
|
||||
- how are default args instantiated
|
||||
- what's the output of the following code, and why?
|
||||
- ||behaves as expected. compile substitutes in the default args at the call
|
||||
site, so the calls become `g(int x=foo())`||.
|
||||
|
||||
```cpp
|
||||
int foo() {
|
||||
static int s = 0;
|
||||
return ++s;
|
||||
}
|
||||
|
||||
void g(int x = foo()) {
|
||||
// ...
|
||||
}
|
||||
|
||||
int main() {
|
||||
g();
|
||||
g();
|
||||
}
|
||||
```
|
||||
|
||||
- does this compile? y or no? ||no - default args not considered in function
|
||||
signature in overload resolution process - call is ambiguous||
|
||||
|
||||
```cpp
|
||||
void print()
|
||||
{
|
||||
std::cout << "void\n";
|
||||
}
|
||||
|
||||
void print(int x=0)
|
||||
{
|
||||
std::cout << "int " << x << '\n';
|
||||
}
|
||||
|
||||
int main() { print(); }
|
||||
```
|
||||
|
||||
### templates
|
||||
|
||||
- how do templates work in the compiler?
|
||||
- ||an internal symbol table - one template blueprint itself does not generate
|
||||
machine code (instantiations do)||
|
||||
- say i have two functions - one regular, one templated. how can i prefer the
|
||||
templated function? do i even need to?
|
||||
- ||if you want to target the templated function, which is more generic and
|
||||
thus not prioritized by the compiler, wrap it in `<>`||
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
void print();
|
||||
void f(bool);
|
||||
|
||||
// ??
|
||||
f(true);
|
||||
f<(bool)>(); // NOTE: bool is optional
|
||||
```
|
||||
|
||||
- what's the output? || 1) 2) 1) - consider the instantiated code per the
|
||||
compiler - one static local variable per template specialization ||
|
||||
|
||||
- what about here? ||second function called. template can create an exact match
|
||||
which is preferred over promotion||.
|
||||
|
||||
```cpp
|
||||
void f(int x) { ... }
|
||||
void f(auto x) { ... }
|
||||
|
||||
// ??
|
||||
f(short{3});
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
template <typename T>
|
||||
void printIDAndValue(T value)
|
||||
{
|
||||
static int id{ 0 };
|
||||
std::cout << ++id << ") " << value << '\n';
|
||||
}
|
||||
|
||||
int main() {
|
||||
printIDAndValue(12);
|
||||
printIDAndValue(13);
|
||||
|
||||
printIDAndValue(14.5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
- ? concepts and generics, best ways to link together?
|
||||
- what's partial ordering of templates?
|
||||
- ? what's the *entire* way compilers resolve function calls?
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
auto add(T x, T y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
auto add(T x, U y) {
|
||||
return x + y;
|
||||
}
|
||||
```
|
||||
|
||||
- what's wrong with this? how do i fix it?
|
||||
- ||add specializations or an else clause with `constexpr`. picture the compiler - it needs to
|
||||
instantiate all proper templates on compilation. in some sense, the
|
||||
compiler is literally executing the code.
|
||||
```cpp
|
||||
template <int N>
|
||||
constexpr long long fibonacci() {
|
||||
static_assert(N >= 0);
|
||||
if (N <= 1) { return N; }
|
||||
return fibonacci<N - 1>() + fibonacci<N - 2>();
|
||||
}
|
||||
```
|
||||
|
||||
- NOTE: this is a sharp edge. skip it, honestly
|
||||
|
||||
- functions instantiated from templates are implicitly ||`inline`||. Why? ||must
|
||||
be so that different, identical specializations in files do not violate the
|
||||
ODR.||
|
||||
- the odr is a compile and/xor link time concept ||and||
|
||||
|
||||
## pointers and references
|
||||
|
||||
- how do references work under the hood?
|
||||
- alias to variable only known to compiler - implicitly dereffed
|
||||
- NEVER reassignable
|
||||
- output?
|
||||
|
||||
```cpp
|
||||
int x = 5;
|
||||
int y = 4;
|
||||
int& z = x;
|
||||
z = y; // x holds value of 4 -> can never reassign alias
|
||||
(*x) = y;
|
||||
```
|
||||
|
||||
- what's the output?
|
||||
- ||A 5 A; reference calls always implicitly resolve to (\*ref) by the compiler - "syntactic sugar". In other words, it's impossible to actually inspect the reference pointer itself.||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
void printAddresses(int val, int& ref)
|
||||
{
|
||||
std::cout << val << '\n';
|
||||
std::cout << &ref << '\n';
|
||||
}
|
||||
|
||||
int main() {
|
||||
int x { 5 };
|
||||
std::cout << "The address of x is: " << &x << '\n';
|
||||
printAddresses(x, x);
|
||||
}
|
||||
```
|
||||
|
||||
- will this compile? ||it has a memory leak - that doesn't mean it won't compile
|
||||
(it is valid c++, sigh)||
|
||||
|
||||
```cpp
|
||||
const std::string& getProgramName() {
|
||||
const std::string programName { "Calculator" };
|
||||
|
||||
return programName;
|
||||
}
|
||||
// automatic storage duration of `programName` - destroyed
|
||||
```
|
||||
|
||||
- auto and what not - name the types, assuming `getRef()` returns `T`:
|
||||
|
||||
- `auto x = getRef()` -> ||T (reference discarded)||
|
||||
- `auto& x = getRef()` -> ||T&. This is known as "reapplying the reference and
|
||||
can also be done with `const`"||
|
||||
- `auto x = getConstRef()` -> ||T (const discarded)||
|
||||
- `auto x = getPointer()` -> ||T\* (pointer kept - notion of
|
||||
converting/dropping is incorrect, its sort of its own type)||
|
||||
- `auto* x = getPointer()` -> ||T\* (pointer kept)||
|
||||
|
||||
- low-level vs. top level const?
|
||||
- ||A top-level const applies to the object itself (e.g. const int x or int* const ptr)||
|
||||
- ||A low-level const applies to the object accessed through a reference or pointer (e.g. const int& ref, const int* ptr).||
|
||||
|
||||
## enums
|
||||
|
||||
- by default, `enum`s are ||unscoped|| which means they ||leak into the
|
||||
scope they're defined in||. For this reason default
|
||||
to `enum`s keyed with the word ||`class`||, or "||scoped||" enums. We just
|
||||
need to access them with the ||scope resolution|| operator.
|
||||
not leak.
|
||||
|
||||
|
||||
- ||bad, good - unscoped do not implicitly convert||
|
||||
```cpp
|
||||
enum class X { A };
|
||||
enum Y { A };
|
||||
|
||||
X::A == 0;
|
||||
Y::A == 0;
|
||||
```
|
||||
|
||||
- ||NO but yes if unscoped, NEVER||
|
||||
|
||||
```cpp
|
||||
void f() {
|
||||
// NOTE: even enum does not work here (both scoped inside)
|
||||
enum class A { B };
|
||||
|
||||
// does this compile?
|
||||
A::B;
|
||||
}
|
||||
|
||||
// this?
|
||||
A::B;
|
||||
```
|
||||
|
||||
## structs/classes
|
||||
|
||||
- `static` in structs means one variable for the lifetime
|
||||
- where do static class/struct vars live in memory? ||not in struct, prob in
|
||||
the data segment||
|
||||
|
||||
- any function implementation in a `struct` is implicitly marked ||`inline`|| - why?
|
||||
- why declare a static struct variable `inline`? ||so you can declare it once inside the struct (C++17+)||
|
||||
- NOTE: only ever makes sense to declare variables as `inline` when done
|
||||
static inside a class - shared, program-living variables. i.e. marking
|
||||
object-local variable as `inline` is nonsensical - it's "already `inline`"
|
||||
- static-static interaction only
|
||||
- no `this` pointer -> must access via `ClassName::{}`
|
||||
|
||||
- structs are like/not like member functions in the sense that they can/cannot
|
||||
be declared in any order
|
||||
- specification default vs. class
|
||||
|
||||
- valid? & why? ||yes, const is part of signature. useful for things like
|
||||
operator overload, const & non-const versions||
|
||||
|
||||
- what is `const` mem func -> ||cannot modift class internals||
|
||||
- When can you not call non-`const` member functions? ||from const objects ->
|
||||
may mutate state||
|
||||
- pretty straightforward, which is why you can/cannot call non-const MF from
|
||||
non-const objects (||can||)
|
||||
|
||||
```cpp
|
||||
// ??
|
||||
class A{
|
||||
void f() const;
|
||||
void f();
|
||||
}
|
||||
```
|
||||
|
||||
### access specification
|
||||
|
||||
- private/public/protected
|
||||
- given your definitions, why is the code below valid or invalid? ||valid -
|
||||
`private` -> *any* object & friend of class (inheritor or not) can touch its members||
|
||||
|
||||
```cpp
|
||||
class A{
|
||||
int x;
|
||||
void f(A a) {
|
||||
// ??
|
||||
a.x;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- structs/class differ in that struct/class AS is ||public/private||
|
||||
- access specification is a ||compile||-time construct and occurs before/after
|
||||
(||after||) method resolution in the compilation process
|
||||
|
||||
- good or bad (||bad - best match, then resolve specification||)
|
||||
|
||||
```cpp
|
||||
struct Gate {
|
||||
private:
|
||||
void calibrate(int);
|
||||
public:
|
||||
void calibrate(double);
|
||||
};
|
||||
|
||||
void run(Gate& g) {
|
||||
// ??
|
||||
g.calibrate(7);
|
||||
}
|
||||
```
|
||||
|
||||
### struct/class memory management
|
||||
|
||||
- struct members can/cannot be reordered and can/cannot have padding inserted
|
||||
- in terms of the following memory model:
|
||||
- <u>code</u>: code itself
|
||||
- <u>data</u>: globals, statics, string literals
|
||||
- <u>stack</u>: stack frames, local vars, etc
|
||||
- <u>heap</u>: heap-allocated things
|
||||
|
||||
```cpp
|
||||
struct Widget {
|
||||
int id; // per-object data
|
||||
std::string name; // per-object data
|
||||
static int total_count; // one global variable
|
||||
static constexpr double pi = 3.14159; // goes in rodata
|
||||
void ping(); // function
|
||||
virtual void vfunc(); // function pointer in vtable
|
||||
};
|
||||
```
|
||||
|
||||
- ... member functions are in (||code, so you don't have multiple
|
||||
per-instantiation||), regular variables in ||stack||, static in ||data||,
|
||||
virtual stuff ||also somewhere in code - like having one virtual pointer||
|
||||
- WHY does this memory management make sense?
|
||||
|
||||
### construction
|
||||
|
||||
- do constructors create objects || no they initialize ||
|
||||
- why not `const`?
|
||||
- follow normal conversion rules
|
||||
|
||||
- ouptput: ||member initializer list always takes precedence||
|
||||
- NOTE: member IL != IL
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
A(int x) : x(x) {}
|
||||
int x{2};
|
||||
};
|
||||
|
||||
// ??
|
||||
A{}.x;
|
||||
```
|
||||
|
||||
- members are initialized in order of declaration in initialize list (why? no
|
||||
idea)
|
||||
|
||||
```cpp
|
||||
class Foo {
|
||||
private:
|
||||
int m_x{};
|
||||
int m_y{};
|
||||
|
||||
public:
|
||||
Foo(int x, int y)
|
||||
// m_x is ALWAYS garbage
|
||||
: m_y { std::max(x, y) }, m_x { m_y }
|
||||
{}
|
||||
};
|
||||
```
|
||||
|
||||
- delegating and chaining constructors can be usefukl for off-loading logic
|
||||
- CALLING CTORS of *other* classes and *our own* in CTORS IS PERFECTLY FINE!
|
||||
|
||||
- more rules:
|
||||
- T/F: if I have constructors but no default, c++ creates an implicit one for
|
||||
me ||F||
|
||||
- T/F: if I have no default constructors, c++ makes ||T||
|
||||
- Say you want to disable copying/default construction. I claim you can just
|
||||
make the methods private. Does this work? ||Yes - but members of the
|
||||
class/inheritors/etc. can still call it -> defeating the purpose - just use
|
||||
`= delete`||
|
||||
|
||||
- anything wrong? ||incompete type - infinite recursion||
|
||||
```cpp
|
||||
class A {
|
||||
A(A a) {}
|
||||
};
|
||||
```
|
||||
|
||||
- why should copy constructors not have side effects? ||if copy elision occurs,
|
||||
the side effects will not. copy elision is immune to the ["as-if" rule](https://en.cppreference.com/w/cpp/language/as_if.html)||
|
||||
|
||||
- what is [(N)RVO](https://en.cppreference.com/w/cpp/language/copy_elision.html) and which c++ concept is behind it? ||copy elision & copy
|
||||
constructors||
|
||||
|
||||
- does this compile? || no - only one user-defined constructor can be applied
|
||||
(trying to go from `std::string` -> `std::string_view` -> `std::string`)||
|
||||
- [user-defined types](https://www.learncpp.com/cpp-tutorial/introduction-to-program-defined-user-defined-types/) are also for STL
|
||||
|
||||
```cpp
|
||||
class Employee {
|
||||
private:
|
||||
std::string m_name{};
|
||||
public:
|
||||
Employee(std::string_view name)
|
||||
: m_name{ name } { }
|
||||
const std::string& getName() const { return m_name; }
|
||||
};
|
||||
|
||||
void printEmployee(Employee e) {
|
||||
std::cout << e.getName();
|
||||
}
|
||||
|
||||
int main() {
|
||||
printEmployee("Joe");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- ? know each constructor syntax - which does this call?
|
||||
|
||||
```cpp
|
||||
Y y = Y(5); // cpp isn't stupid -> calls Y::Y(const& y), the copy constructor - not default + assigned
|
||||
Y y = Y(); // default & copy, but copy elided (c++17+) -> just default
|
||||
Y o;
|
||||
Y y(o); // textbook copy
|
||||
Y y = Y(Y()); // one defeault - BOTH elided
|
||||
```
|
||||
|
||||
- `explicit` - only accept exact value type (no implicit conversions)
|
||||
- why use `explicit` -> implicit conversions
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
int a;
|
||||
A(int a) : a(a) {}
|
||||
void meth(A a) {}
|
||||
};
|
||||
|
||||
A a = A(true); // this is valid when A::A(int) is not explicit
|
||||
a.meth(A(false)); // so i can do this too
|
||||
```
|
||||
- called by `static_cast` just fine, too
|
||||
|
||||
### this pointer
|
||||
|
||||
- "Every non-static member function has an implicit parameter called this."
|
||||
- how does `this` and implicit `this` work?
|
||||
- inserted implicitly
|
||||
- what's the type of `this` in non-const/const member functions? ||
|
||||
`TheClass\* const` (const pointer - you can still change underlying object)/const TheClass\* const (you cannot change underlying object, so pointer to
|
||||
const)||
|
||||
- NOTE: references didn't exist when c++ was made, so even tho it should be a
|
||||
reference it's not
|
||||
|
||||
```cpp
|
||||
class MethodChain {
|
||||
MethodChain& mc() {
|
||||
// deref -> automatically aliased in return type
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- ODR again - why does defining classes in headers "just work?" - because class
|
||||
member functions defined ||& implemented fully in the header|| are ||implicitly marked as `inline`||
|
||||
- I could just define an entire class in a header - why not? ||organization +
|
||||
increased compile time -> recompile header + all deps on change, rather than
|
||||
just cpp source file)
|
||||
- why do class variables and other things not need to be marked `inline`
|
||||
||***member functions have external linkage by default***. other stuff does
|
||||
not and is a per-object local storage - is has NO linkage||
|
||||
|
||||
### more `static`
|
||||
|
||||
- static vars are/are not associated with the lifetime of a class ||are not -
|
||||
start & end of program - can access w/ 0 instances||
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
static x;
|
||||
};
|
||||
|
||||
A::x; // valid
|
||||
```
|
||||
|
||||
- say you want to shield static class vars - how? ||make private - access
|
||||
specifiers trump||
|
||||
|
||||
- static *member functions* have/don't have a `this` pointer ||don't||
|
||||
- therefore, they can/cannot call non-static functions - why? ||cannot -
|
||||
non-static member functions need an implicit this object point to operate
|
||||
on, and statics do not have this||
|
||||
|
||||
# [beginning c++ 23: beginner to pro](https://www.amazon.com/Beginning-C-23-Beginner-Pro/dp/1484293428)
|
||||
3
perf-cpp/readme.md
Normal file
3
perf-cpp/readme.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# performance
|
||||
|
||||
c++ and performance notes and resources
|
||||
9
perf-cpp/scripts/.clang-format
Normal file
9
perf-cpp/scripts/.clang-format
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
BasedOnStyle: Google
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
35
perf-cpp/scripts/.clangd
Normal file
35
perf-cpp/scripts/.clangd
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
CompileFlags:
|
||||
Add:
|
||||
-O2
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wformat=2
|
||||
-Wfloat-equal
|
||||
-Wlogical-op
|
||||
-Wshift-overflow=2
|
||||
-Wnon-virtual-dtor
|
||||
-Wold-style-cast
|
||||
-Wcast-qual
|
||||
-Wuseless-cast
|
||||
-Wno-sign-promotion
|
||||
-Wcast-align
|
||||
-Wunused
|
||||
-Woverloaded-virtual
|
||||
-Wconversion
|
||||
-Wsign-conversion
|
||||
-Wmisleading-indentation
|
||||
-Wduplicated-cond
|
||||
-Wduplicated-branches
|
||||
-Wlogical-op
|
||||
-Wnull-dereference
|
||||
-Wformat=2
|
||||
-Wformat-overflow
|
||||
-Wformat-truncation
|
||||
-Wdouble-promotion
|
||||
-Wundef
|
||||
-DLOCAL
|
||||
-Wno-unknown-pragmas
|
||||
-e -std=c++23
|
||||
-e -std=c++23
|
||||
9
perf-cpp/scripts/a.cc
Normal file
9
perf-cpp/scripts/a.cc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "a.hh"
|
||||
|
||||
int main() {
|
||||
std::cout << add();
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
perf-cpp/scripts/a.hh
Normal file
3
perf-cpp/scripts/a.hh
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
int add() {return 1;}
|
||||
29
perf-cpp/scripts/bitset.cc
Normal file
29
perf-cpp/scripts/bitset.cc
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
|
||||
std::bitset<4> rotl(std::bitset<4> bits) {
|
||||
return (bits << 1) | (bits >> 3);
|
||||
}
|
||||
|
||||
void william() {
|
||||
int will;
|
||||
|
||||
if (69)
|
||||
int will;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::bitset<4> bits1{ 0b0001 };
|
||||
std::cout << rotl(bits1) << '\n';
|
||||
|
||||
std::bitset<4> bits2{ 0b1001 };
|
||||
std::cout << rotl(bits2) << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
perf-cpp/scripts/ch11.cc
Normal file
48
perf-cpp/scripts/ch11.cc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Write a constexpr function template with a non-type template parameter that
|
||||
returns the factorial of the template argument. The following program should
|
||||
fail to compile when it reaches factorial<-3>().
|
||||
|
||||
*/
|
||||
|
||||
template <int N>
|
||||
constexpr long long fibonacci() {
|
||||
static_assert(N >= 0);
|
||||
if constexpr (N <= 1) {
|
||||
return N;
|
||||
} else {
|
||||
return fibonacci<N - 1>() + fibonacci<N - 2>();
|
||||
}
|
||||
}
|
||||
|
||||
// int main() {
|
||||
// static_assert(fibonacci<1LL>() == 1);
|
||||
// // static_assert(factorial<3>() == 6);
|
||||
// // static_assert(factorial<5>() == 120);
|
||||
//
|
||||
// // fibonacci<-3>();
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <typename T>
|
||||
T add(T x, T y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T mult(T t, int N) {
|
||||
return t * N;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << add(2, 3) << '\n';
|
||||
std::cout << add(1.2, 3.4) << '\n';
|
||||
|
||||
std::cout << mult(2, 3) << '\n';
|
||||
std::cout << mult(1.2, 3) << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
perf-cpp/scripts/ch15.cc
Normal file
50
perf-cpp/scripts/ch15.cc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Question #1
|
||||
|
||||
Write a class template named Triad that has 3 private data members with
|
||||
independent type template parameters. The class should have a constructor,
|
||||
access functions, and a print() member function that is defined outside the
|
||||
class.
|
||||
|
||||
The following program should compile and run:
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
class Triad {
|
||||
private:
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
T3 t3;
|
||||
|
||||
public:
|
||||
explicit Triad() {
|
||||
}
|
||||
explicit Triad(T1 t1, T2 t2, T3 t3) : t1(t1), t2(t2), t3(t3) {
|
||||
}
|
||||
T1 first() { return t1; }
|
||||
void print() ;
|
||||
~Triad() {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void Triad<T1, T2, T3>::print() {
|
||||
std::cout << '[' << t1 << ", " << t2 << ", " << t3 << "]\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
Triad t1{1, 2, 3};
|
||||
t1.print();
|
||||
std::cout << '\n';
|
||||
std::cout << t1.first() << '\n';
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
const Triad t2{1, 2.3, "Hello"s};
|
||||
t2.print();
|
||||
std::cout << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
perf-cpp/scripts/ch4.cc
Normal file
38
perf-cpp/scripts/ch4.cc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Write the following program: The user is asked to enter 2 floating point numbers (use doubles). The user is then asked to enter one of the following mathematical symbols: +, -, *, or /. The program computes the answer on the two numbers the user entered and prints the results. If the user enters an invalid symbol, the program should print nothing.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
double x, y;
|
||||
std::cout << "enter x: "<<'\n';
|
||||
std::cin >> x;
|
||||
std::cout << "enter x: "<<'\n';
|
||||
std::cin >> y;
|
||||
std::cout << "enter symbol " << '\n';;
|
||||
char symbol;
|
||||
std::cin >> symbol;
|
||||
|
||||
double ans;
|
||||
switch (symbol) {
|
||||
case '+':
|
||||
ans = x + y;
|
||||
break;
|
||||
case '-':
|
||||
ans = x - y;
|
||||
break;
|
||||
case '*':
|
||||
ans = x * y;
|
||||
break;
|
||||
case '/':
|
||||
ans = x / y;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
std::cout << "answer: " << ans << '\n';
|
||||
return 0;
|
||||
}
|
||||
51
perf-cpp/scripts/ch5.cc
Normal file
51
perf-cpp/scripts/ch5.cc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
template <std::integral T>
|
||||
T binexp(T base, T exponent, T mod) {
|
||||
assert(mod > 0 && exponent > 0);
|
||||
|
||||
T product{1};
|
||||
T multiplier{base % mod};
|
||||
|
||||
while (exponent > 0) {
|
||||
if ((exponent & 1) != 0) {
|
||||
product = (multiplier * product) % mod;
|
||||
}
|
||||
multiplier = (multiplier * multiplier) % mod;
|
||||
exponent >>= 1;
|
||||
}
|
||||
|
||||
return product;
|
||||
}
|
||||
|
||||
int main() {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
std::string S{"hello"};
|
||||
std::string_view s{S};
|
||||
S.~basic_string();
|
||||
|
||||
// double ub - free + string view dereferencing destroyed object
|
||||
// std::cout << s << '\n' ;
|
||||
|
||||
std::cout << -5 / 2 << '\n';
|
||||
|
||||
using namespace std;
|
||||
long double ld = pow((long double)10, 18); // computed in floating point
|
||||
long long ll = (long long)ld; // cast back to integer
|
||||
|
||||
cout << fixed << setprecision(0);
|
||||
cout << "pow(10,18) as long double: " << ld << "\n";
|
||||
cout << "cast to long long: " << ll << "\n";
|
||||
cout << "Should be exactly: " << 1000000000000000000LL << "\n";
|
||||
|
||||
std::cout << binexp(2, 5, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
20
perf-cpp/scripts/ch6.cc
Normal file
20
perf-cpp/scripts/ch6.cc
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
/*
|
||||
Write a program that asks the user to input an integer, and tells the user whether the number is even or odd. Write a constexpr function called isEven() that returns true if an integer passed to it is even, and false otherwise. Use the remainder operator to test whether the integer parameter is even. Make sure isEven() works with both positive and negative numbers
|
||||
.*/
|
||||
|
||||
constexpr bool isEven(std::int32_t number) {
|
||||
return number % 2 == 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "input an integer: \n";
|
||||
std::int32_t x{};
|
||||
std::cin >> x;
|
||||
|
||||
std::cout << std::boolalpha << isEven(x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
perf-cpp/scripts/chapter-1.cc
Normal file
18
perf-cpp/scripts/chapter-1.cc
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Enter a number: \n";
|
||||
|
||||
int n;
|
||||
std::cin >> n;
|
||||
|
||||
int m;
|
||||
|
||||
std::cout << "Enter another number: \n";
|
||||
|
||||
std::cin >> m;
|
||||
|
||||
std::cout << "Diff: " << n - m << "; Sum: " << n + m << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
2
perf-cpp/scripts/compile_flags.txt
Normal file
2
perf-cpp/scripts/compile_flags.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
-O0
|
||||
-std=c++20
|
||||
14
perf-cpp/scripts/consteval.cc
Normal file
14
perf-cpp/scripts/consteval.cc
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <iostream>
|
||||
|
||||
consteval int foo(int x) {
|
||||
if (x <= 1) return x;
|
||||
return foo(x - 1) + foo(x - 2);
|
||||
}
|
||||
|
||||
int main() {
|
||||
constexpr int x = foo(3);
|
||||
|
||||
static_assert(x != foo(4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
10
perf-cpp/scripts/conversion.cc
Normal file
10
perf-cpp/scripts/conversion.cc
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <iostream>
|
||||
|
||||
void f(double) { std::cout << "double\n"; }
|
||||
void f(int) { std::cout << "long\n"; }
|
||||
|
||||
int main() {
|
||||
short x = 5;
|
||||
f(x); // Which one?
|
||||
}
|
||||
|
||||
14
perf-cpp/scripts/debug_flags.txt
Normal file
14
perf-cpp/scripts/debug_flags.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
-g3
|
||||
-fsanitize=address,undefined
|
||||
-fsanitize=float-divide-by-zero
|
||||
-fsanitize=float-cast-overflow
|
||||
-fno-sanitize-recover=all
|
||||
-fstack-protector-all
|
||||
-fstack-usage
|
||||
-fno-omit-frame-pointer
|
||||
-fno-inline
|
||||
-ffunction-sections
|
||||
-D_GLIBCXX_DEBUG
|
||||
-D_GLIBCXX_DEBUG_PEDANTIC
|
||||
-DLOCAL
|
||||
-std=c++23
|
||||
50
perf-cpp/scripts/enum-class-quiz.cc
Normal file
50
perf-cpp/scripts/enum-class-quiz.cc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include <iostream>
|
||||
|
||||
struct Counter {
|
||||
inline static int x = 1;
|
||||
static void bump() { ++x; }
|
||||
};
|
||||
|
||||
struct Counter2 : Counter {
|
||||
inline static int x = 100;
|
||||
static void bump() { x += 10; }
|
||||
};
|
||||
|
||||
enum E { A = 1, B = 2 };
|
||||
|
||||
struct S {
|
||||
enum E { B = 3, C = 4 };
|
||||
static int f() { return B; }
|
||||
};
|
||||
|
||||
enum class M : unsigned char { A = 250, B, C };
|
||||
|
||||
int g() {
|
||||
int B = 40;
|
||||
return S::f() + B;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Counter::bump();
|
||||
Counter2::bump();
|
||||
|
||||
// 112
|
||||
int t1 = Counter::x + Counter2::x;
|
||||
|
||||
// 43
|
||||
int u1 = g();
|
||||
|
||||
int B = 7;
|
||||
// 9
|
||||
int t2 = B + ::B;
|
||||
|
||||
int d;
|
||||
{
|
||||
using enum M;
|
||||
// 251 - 250 = 1?
|
||||
d = static_cast<int>(B) - static_cast<int>(A);
|
||||
}
|
||||
|
||||
std::cout << t1 << " " << u1 << " " << t2 << " " << d << "\n";
|
||||
}
|
||||
|
||||
2
perf-cpp/scripts/io/chapter-1.in
Normal file
2
perf-cpp/scripts/io/chapter-1.in
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
1
|
||||
2
|
||||
7
perf-cpp/scripts/io/chapter-1.out
Normal file
7
perf-cpp/scripts/io/chapter-1.out
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Enter a number:
|
||||
Enter another number:
|
||||
Diff: -1; Sum: 3
|
||||
|
||||
[code]: 0
|
||||
[time]: 2.52771 ms
|
||||
[debug]: false
|
||||
0
perf-cpp/scripts/io/file.in
Normal file
0
perf-cpp/scripts/io/file.in
Normal file
14
perf-cpp/scripts/io/file.out
Normal file
14
perf-cpp/scripts/io/file.out
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
file.cc: In function ‘int main()’:
|
||||
file.cc:66:23: error: narrowing conversion of ‘3.0e+0’ from ‘double’ to ‘int’ [-Wnarrowing]
|
||||
66 | vector<int> a= { 3.0};
|
||||
| ^
|
||||
file.cc: At global scope:
|
||||
file.cc:39:13: warning: ‘void YES()’ defined but not used [-Wunused-function]
|
||||
39 | static void YES() {
|
||||
| ^~~
|
||||
file.cc:35:13: warning: ‘void NO()’ defined but not used [-Wunused-function]
|
||||
35 | static void NO() {
|
||||
| ^~
|
||||
cc1plus: note: unrecognized command-line option ‘-Wno-sign-promotion’ may have been intended to silence earlier diagnostics
|
||||
|
||||
[code]: 1
|
||||
32
perf-cpp/scripts/loops.cc
Normal file
32
perf-cpp/scripts/loops.cc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
void call_for() {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
std::cout << (1 + 123 * 6 ^ 3 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
void call_while() {
|
||||
int i = 0;
|
||||
while (i < 5) {
|
||||
std::cout << (1 + 123 * 6 ^ 3 << 2);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void call_do_while() {
|
||||
int i = 0;
|
||||
do {
|
||||
std::cout << (1 + 123 * 6 ^ 3 << 2);
|
||||
++i;
|
||||
} while (i < 5);
|
||||
}
|
||||
|
||||
int main() {
|
||||
call_for();
|
||||
call_while();
|
||||
call_do_while();
|
||||
|
||||
return 0;
|
||||
}
|
||||
30
perf-cpp/scripts/makefile
Normal file
30
perf-cpp/scripts/makefile
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
.PHONY: run debug clean setup init
|
||||
|
||||
VERSION ?= 20
|
||||
|
||||
SRC = $(word 2,$(MAKECMDGOALS))
|
||||
|
||||
.SILENT:
|
||||
|
||||
run:
|
||||
sh scripts/run.sh $(SRC)
|
||||
|
||||
debug:
|
||||
sh scripts/debug.sh $(SRC)
|
||||
|
||||
clean:
|
||||
rm -rf build/*
|
||||
|
||||
setup:
|
||||
test -d build || mkdir -p build
|
||||
test -d io || mkdir -p io
|
||||
test -d scripts || mkdir -p scripts
|
||||
test -f .clang-format || cp $(HOME)/.config/cp-template/.clang-format .
|
||||
test -f compile_flags.txt || cp $(HOME)/.config/cp-template/compile_flags.txt . && echo -std=c++$(VERSION) >>compile_flags.txt
|
||||
test -f .clangd || cp $(HOME)/.config/cp-template/.clangd . && echo -e "\t\t-std=c++$(VERSION)" >>.clangd
|
||||
|
||||
init:
|
||||
make setup
|
||||
|
||||
%:
|
||||
@:
|
||||
29
perf-cpp/scripts/scripts/debug.sh
Normal file
29
perf-cpp/scripts/scripts/debug.sh
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ./scripts/utils.sh
|
||||
|
||||
SRC="$1"
|
||||
BASE=$(basename "$SRC" .cc)
|
||||
INPUT="${BASE}.in"
|
||||
OUTPUT="${BASE}.out"
|
||||
DBG_BIN="${BASE}.debug"
|
||||
|
||||
test -d build || mkdir -p build
|
||||
test -d io || mkdir -p io
|
||||
|
||||
test -f "$INPUT" && test ! -f "io/$INPUT" && mv "$INPUT" "io/"
|
||||
test -f "$OUTPUT" && test ! -f "io/$OUTPUT" && mv "$OUTPUT" "io/"
|
||||
|
||||
test -f "io/$INPUT" || touch "io/$INPUT"
|
||||
test -f "io/$OUTPUT" || touch "io/$OUTPUT"
|
||||
|
||||
INPUT="io/$INPUT"
|
||||
OUTPUT="io/$OUTPUT"
|
||||
DBG_BIN="build/$DBG_BIN"
|
||||
|
||||
compile_source "$SRC" "$DBG_BIN" "$OUTPUT" @debug_flags.txt
|
||||
CODE=$?
|
||||
test $CODE -gt 0 && exit $CODE
|
||||
|
||||
execute_binary "$DBG_BIN" "$INPUT" "$OUTPUT" true
|
||||
exit $?
|
||||
29
perf-cpp/scripts/scripts/run.sh
Normal file
29
perf-cpp/scripts/scripts/run.sh
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ./scripts/utils.sh
|
||||
|
||||
SRC="$1"
|
||||
BASE=$(basename "$SRC" .cc)
|
||||
INPUT="${BASE}.in"
|
||||
OUTPUT="${BASE}.out"
|
||||
RUN_BIN="${BASE}.run"
|
||||
|
||||
test -d build || mkdir -p build
|
||||
test -d io || mkdir -p io
|
||||
|
||||
test -f "$INPUT" && test ! -f "io/$INPUT" && mv "$INPUT" "io/"
|
||||
test -f "$OUTPUT" && test ! -f "io/$OUTPUT" && mv "$OUTPUT" "io/"
|
||||
|
||||
test -f "io/$INPUT" || touch "io/$INPUT"
|
||||
test -f "io/$OUTPUT" || touch "io/$OUTPUT"
|
||||
|
||||
INPUT="io/$INPUT"
|
||||
OUTPUT="io/$OUTPUT"
|
||||
RUN_BIN="build/$RUN_BIN"
|
||||
|
||||
compile_source "$SRC" "$RUN_BIN" "$OUTPUT" ""
|
||||
CODE=$?
|
||||
test $CODE -gt 0 && exit $CODE
|
||||
|
||||
execute_binary "$RUN_BIN" "$INPUT" "$OUTPUT"
|
||||
exit $?
|
||||
61
perf-cpp/scripts/scripts/utils.sh
Normal file
61
perf-cpp/scripts/scripts/utils.sh
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/sh
|
||||
|
||||
execute_binary() {
|
||||
binary="$1"
|
||||
input="$2"
|
||||
output="$3"
|
||||
is_debug="$4"
|
||||
|
||||
start=$(date '+%s.%N')
|
||||
if [ -n "$is_debug" ]; then
|
||||
asan="$(ldconfig -p | grep libasan.so | head -n1 | awk '{print $4}')"
|
||||
LD_PRELOAD="$asan" timeout 2s ./"$binary" <"$input" >"$output" 2>&1
|
||||
else
|
||||
timeout 2s ./"$binary" <"$input" >"$output" 2>&1
|
||||
fi
|
||||
CODE=$?
|
||||
end=$(date '+%s.%N')
|
||||
truncate -s "$(head -n 1000 "$output" | wc -c)" "$output"
|
||||
|
||||
if [ $CODE -ge 124 ]; then
|
||||
MSG=''
|
||||
case $CODE in
|
||||
124) MSG='TIMEOUT' ;;
|
||||
128) MSG='SIGILL' ;;
|
||||
130) MSG='SIGABRT' ;;
|
||||
131) MSG='SIGBUS' ;;
|
||||
136) MSG='SIGFPE' ;;
|
||||
135) MSG='SIGSEGV' ;;
|
||||
137) MSG='SIGPIPE' ;;
|
||||
139) MSG='SIGTERM' ;;
|
||||
esac
|
||||
[ $CODE -ne 124 ] && sed -i '$d' "$output"
|
||||
test -n "$MSG" && printf '\n[code]: %s (%s)' "$CODE" "$MSG" >>"$output"
|
||||
else
|
||||
printf '\n[code]: %s' "$CODE" >>"$output"
|
||||
fi
|
||||
|
||||
printf '\n[time]: %s ms' "$(awk "BEGIN {print ($end - $start) * 1000}")" >>$output
|
||||
test -n "$is_debug" && is_debug_string=true || is_debug_string=false
|
||||
printf '\n[debug]: %s' "$is_debug_string" >>$output
|
||||
return $CODE
|
||||
}
|
||||
|
||||
compile_source() {
|
||||
src="$1"
|
||||
bin="$2"
|
||||
output="$3"
|
||||
flags="$4"
|
||||
|
||||
test -f "$bin" && rm "$bin" || true
|
||||
g++ @compile_flags.txt $flags "$src" -o "$bin" 2>"$output"
|
||||
CODE=$?
|
||||
|
||||
if [ $CODE -gt 0 ]; then
|
||||
printf '\n[code]: %s' "$CODE" >>"$output"
|
||||
return $CODE
|
||||
else
|
||||
echo '' >"$output"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
40
perf-cpp/scripts/struct.cc
Normal file
40
perf-cpp/scripts/struct.cc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include <iostream>
|
||||
|
||||
class S {
|
||||
// void print() const { a = 3; std::cout << S::a << '\n'; }
|
||||
int a = 0;
|
||||
|
||||
public:
|
||||
S(int x) : x(x) {
|
||||
}
|
||||
int x{2};
|
||||
};
|
||||
|
||||
class X {
|
||||
int x;
|
||||
|
||||
public:
|
||||
X() : x(0) {};
|
||||
void get() {
|
||||
std::cout << "x; " << x << '\n';
|
||||
}
|
||||
int& y() {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
// S{}.print();
|
||||
// S.x;
|
||||
// std::cout << S{3}.x << '\n';
|
||||
|
||||
X x;
|
||||
auto& ret = x.y();
|
||||
|
||||
// ++ret;
|
||||
|
||||
x.get();
|
||||
|
||||
// X x;
|
||||
return 0;
|
||||
}
|
||||
39
perf-cpp/scripts/switch.cc
Normal file
39
perf-cpp/scripts/switch.cc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include <iostream>
|
||||
|
||||
extern volatile int sink;
|
||||
|
||||
int g(int x) {
|
||||
if (x == 100) sink = 42;
|
||||
else if (x == 101) sink = 7;
|
||||
else if (x == 102) sink = 99;
|
||||
else if (x == 103) sink = 13;
|
||||
else if (x == 104) sink = 5;
|
||||
else if (x == 105) sink = 88;
|
||||
else if (x == 106) sink = 21;
|
||||
else if (x == 107) sink = 60;
|
||||
else if (x == 108) sink = 33;
|
||||
else if (x == 109) sink = 1;
|
||||
else if (x == 110) sink = 77;
|
||||
else if (x == 111) sink = 12;
|
||||
else if (x == 112) sink = 54;
|
||||
else if (x == 113) sink = 31;
|
||||
else if (x == 114) sink = 73;
|
||||
else if (x == 115) sink = 16;
|
||||
else sink = -1;
|
||||
return sink;
|
||||
}
|
||||
|
||||
int main() {
|
||||
char x;
|
||||
std::cin >> x;
|
||||
|
||||
if (x == 'x') {
|
||||
std::cout << "hi\n";
|
||||
} else {
|
||||
if (x == 'y') {
|
||||
std::cout << "sup\n";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue