C _STL_Tools - RicoJia/notes GitHub Wiki

========================================================================

Numeric & Math

========================================================================

  1. cmath

    • ceil, floor
    • cos, sin
  2. std::equal() 比较两个vector

  3. limits

    #include <limits>
    cout << numeric_limits<double>::min() << endl;
    cout << numeric_limits<double>::max() << endl;
    double a = std::numeric_limits<double>::infinity(); //  > or < both gives you false!
    • != is false, == is true.
    • (for int you don't have a true infinity std::numeric_limits<int>max(); )
    • isinf:
      #include <cmath>
      isinf(double)
    • std::numeric_limits<double>::min()): this is 10 e^-308
  4. std::abs() in only takes in integers, but in it takes in floats. you can use std::fabs() for floating point uses.

    • std::abs vs std::fabs
      • cmath's abs(-2.5) outputs 2. std::abs will output 2.5, because it has type overload.;
      • abs and fabs are there for backward compatibility. So just use std::abs., can be used directly
  5. std::count(beg_itr, end_itr, 'target');

  6. std::isnan()

  7. std::numeric_limits::quiet_NaN();

  8. std::plus

    #include <functional>   //std::plus
    //Definition
    template <typename T>
    struct plus{
        T operator(const T& x, const T& y){
            return x + y; 
          }
      }
    
    // Example
    std::transform(arr1, arr1 + 4, arr2, results, std::plus<int>);  //C++ 11
    std::transform(arr1, arr1 + 4, arr2, results, std::plus<>);  //C++ 14
    • standard operator's type can be omitted in C++14, so std::plus<int> -> std::plus<>
  9. sqrt(1.5) 直接用

Complex

  1. std::norm(complex<double>{motion_vector.at(i), motion_vector.at(i+1)}); finding squared norm.

========================================================================

Algorithm

========================================================================

  1. std::accumulate acceptable forms:
    1. simple summing
      #include <numeric>
      sum = std::accumulate(vec.begin(), vec.end(), 0.0); 
      • Note: sum will be casted to int, even if std::vector<double> vec :
      sum = std::accumulate(vec.begin(), vec.end(), 0); 
    2. Other accumulative tasks:
      T accumulate(Iterator first, Iterator Last, T init, Binary_Operation op){
        for(; first != last; ++first){
          init = op(std::move(init), *first); 
        }
      }
      • E.g,
      std::accumulate(vec.begin(), vec.end(), 1, [](int product, int b){return product*b}); 

========================================================================

Algorithm

======================================================================== 2. max_element

#include <algorithm>
std::max_element(begin_itr, end_itr, policy)
**注意, 如果vector 自己是空的话,max_element 本身只是返回vec.end(), 但是你要dereference 的话,那么你就会有error!**
  1. std::min()

    // find min between 2 nums
    #include <algorithm>
    std::min(a,b, [](A& a, B&b){return a.something \<\ b.something}; ); 
    // find min in a list
    std::min({a,b,c...} compare)  // returns the smallest in the initializer list!
    • std::min(unsigned int, int) is not allowed!
  2. *在用partition, transform 等时,你的predicate 的argument是 (itr), 而不是iterator 本身

  3. Transform

    1. unary operations
    // Definition
    transform(Iterator inputBegin, Iterator inputEnd, 
             Iterator OutputBegin, unary_operation) 
    // example: increment a number in an array
    int arr[] = {1,2,3,4}; 
    n = sizeof(arr)/sizeof(int); 
    std::transform(arr, arr+n, arr, [](int x){return x+1;})
    1. binary operation
    // Definition
    transform(Iterator inputBegin1, Iterator inputEnd1, Iterator inputBegin2, 
              Iterator outputBegin, binary_operation)
    // Example: arr_1 - arr 2 
    int arr_1[] = {1,2,3,4}; 
    int arr_2[] = {1,2,3,4}; 
    int result[5]; 
    std::transform(arr_1, arr_1+4, arr_2, result, [](int i1, i2){return i1 - i2; }); 
    • std::transform(It1 it1_begin, It1, it1_end, It2 it2_end, It3 out_begin, [](const Type1& a, const Type2&b){return something})
  4. std::swap() in algorithm

  5. For each

    • std::for_each
    #include<algorithm>
    std::for_each(begin(numbers), end(numbers), [](int num){do stuff});
    • for each loop: array will also return a reference/copy!
        int arr[] {1,2,3};
        for (int x : arr) cout<<x;
    • std::for_each
      #include <algorithm>
      void func (const int& i){};
      int main(){
        std::vector<int> vec {1,2,3};
        std::for_each(vec.begin(), vec.end(), &func);
      }
  6. std::find_if

    #include <algorithm>
    std::vector<int>::iterator it = std::find_if(vec.begin(), vec.end(), if_true); 
  7. std::partition: reorder elements [beg, end), elements satify the predicate will be put left (inside order NOT preserved). returns the first element of the second group.

    #include <algorithm>
    // Bad Example: 
    auto first_it = std::partition(ls.begin(), ls.end(), [&pivot](const int& i){return i < pivot; }); // is first_it the pivot? Not necessarily, because the order of the right-hand side might be screwed up!
    1. std::partition: all members in that range [) wil be modified, so don't change that range. Internally, it's also blocking.

========================================================================

Iterator

========================================================================

  1. std::advance
    1. iterator only? yes.
    #include <iterator>
    std::advance(it, distance);
    1. what if out of limits?
    • if distance < 0, decrement
    • If distance out of bounds,undefined behavior
  • increment for loop not by ++
    for(auto start = id; start < test_vec.size(); start += num_threads){}
  1. reminder: for(auto i: map) returns a std::pair, not iterator! If returning iterator, then you need *it.

========================================================================

Functional

========================================================================

  1. std::hash: #include <functional>
    • works well with prime nums?

========================================================================

chrono

========================================================================

  1. Chrono lib addresses different systems have different clocks, and precision might be different. So it separates duration, and point of time from specific clocks.

    • is both the header file and the namespace
    • Contains all time-handling facilities used by thread library
    • Wall time vs CPU time, and a super good doc
  2. clock:

    1. has:
      • std::chrono::steady_clock: cannot be adjusted? ticks at mono-rate, like a stop-watch
      • std::chrono::system_clock: same as the one in tool bar, so affected by "day-light saving"
      • std::chrono::high_resolution_clock: smallest possible tick period, high_resolution_clock may be a synonym for steady_clock and system_clock
      • except for steady_clock, adjustments are applied to accomodate local clock drift. So a call now() may return a value earlier than a previous now(). (think about multi-threaded case)
    2. class members:
      • now (time_point): time_point <system_clock> start = system_clock::now();, a static function
      • period: a ratio, tick period
        cout<<std::chrono::system_clock::period::num<<" | "<<std::chrono::system_clock::period::den<<endl;    // see 1 | 1000000000, 
        // std::ratio must be printed this way
        • Except for std::chrono::steady_clock, this period is not guaranteed to be the steady period!
      • is_steady
        cout<<std::chrono::system_clock::is_steady<<endl;
  3. duration:

    1. std::chrono::duration<double>
    2. std::chrono::milliseconds, std::chrono::seconds, std::chrono::hours
      • are duration</*signed integer type of at least 45 bits*/, std::milli>
    3. Define your own type: - ratio is respective to second
      using short_min = std::chrono::duration<short, std::ratio<60,1>>    // a min in short int
      using double_ms = std::chrono::duration<double, std::ratio<1,1000>>    // a millisecond in double
      
      short_min sm(2);
      cout <<"sm count "<<sm.count()<<endl;     // see 2
    4. class members:
      1. count(): double for duration, int for milliseconds and others
        milliseconds m(30); 
        cout<<m.count()<<endl;    //30
        • time_since_epoch.count(): returns the number of periods passed, not in seconds!
          std::cout << "periods: " << dtn.count() << std::endl;
          std::cout << "seconds: " << dtn.count() * system_clock::period::num / system_clock::period::den;
          // periods: 1338280396212871
          // seconds: 1338280396
      2. period, which is a std::ratio, can be used for conversion
        m.count() * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den   //(num for numerator, den for denominator, ALL IN INT, here this ratio is 1:1000, so RELATIVE TO SECONDS)
      3. arithmatic:
        30*std::chrono::seconds(1);  //equivalent to std::chrono::seconds(30)
        minutes(1) - seconds(55);     // get seconds(5)
  4. conversions:

    • seconds -> timepoint: std::chrono::system_clock::time_point tp{std::chrono::seconds{timeSeconds}};
    • hours -> seconds, implicit, no explicit conversion required.
    • timepoint cast:
      auto start_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(start_).time_since_epoch().count();
    • From seconds to hours, needs explicit conversion using duration_cast, and will be truncated
      std::chrono::milliseconds ms(54802); 
      std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(ms);
      cout<<s.count()<<endl;      //see 54
    • time_since_epoch -> time in seconds (python's time.time()): seconds from epoch in double
      cout<<std::chrono::duration_cast<seconds>(system_clock::now().time_since_epoch()).count() / 1.0 <<endl;
    • duration -> time in double:
    duration<double> time_stamp = system_clock::now().time_since_epoch(); 
    payload["timestamp"] = time_stamp.count(); 
  5. std::chrono::time_point<std::chrono::system_clock>

    • difference must be std::duration<double>
      std::chrono::time_point<std::chrono::system_clock> start, end; 
      start = std::chrono::system_clock::now(); 
      end = std::chrono::system_clock::now(); 
      std::chrono::duration<double> diff1 = end - start; 
      std::chrono::duration<int> diff2 = end - start;     //ERROR: not defined
      cout<<"elapsed time in seconds: "<<diff1.count()<<endl;
    • std::chrono::duration<int> = time_point::time_since_epoch()
    • std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes> returns duration in minutes
    • can do std::chrono::high_resolution_clock::now() + std::chrono::seconds(500)

Older time formats

  1. std::time_t: almost (not guaranteed) that will hold number of seconds since epoch

    std::time_t end_time = std::chrono::system_clock::to_time_t(end);     // see 1629678991
    • get formatted time:
    std::string get_formatted_time(const time_point<system_clock>& t) {
        // the format is like 23-Aug-2021-22-41-10
        time_t int_time = system_clock::to_time_t(t);
        tm* local_time = localtime(&int_time);
        char buffer[80];
        strftime(buffer, 80, "%d-%b-%Y-%H-%M-%S", local_time);
        return buffer;
    }
  2. std::ctime(std::time_t*)

    cout<<std::ctime(&end_time)<<endl;  //Mon Aug 23 00:53:41 2021
  3. there are SI ratios:

    • std::atto 10^-18
    • std::exa 10^18
  4. Profile Timer - no "correct way", just what ppl use:

    struct Profiler_Timer{
       Profiler_Timer(const std::string& name = ""): name_(name){
           start_ = std::chrono::high_resolution_clock::now();  
       } 
    
       ~Profiler_Timer(){
          auto end = std::chrono::high_resolution_clock::now();
          auto start_us = std::chrono::time_point_cast<std::chrono::microseconds>(start_).time_since_epoch().count(); 
          auto end_us = std::chrono::time_point_cast<std::chrono::microseconds>(end).time_since_epoch().count(); 
          std::cout<<name_<<"finishes in "<< (end_us - start_us)/1000000.0<<"s"<<endl; 
       }
    
       std::chrono::time_point<std::chrono::high_resolution_clock> start_; 
       std::string name_; 
    };
    

========================================================================

Literals

========================================================================

  1. Classic Literals

    42    //int
    2.4   //double
    3.2F  //float
    'w'   //char
    32ULL //unsigned long long 
    0xD0  //Hex
    "cd"  //c-style string 
  2. std::literals: No underscores

    • "Hello"s, std::string literal (not c-string literal!, C++14)
      #include <iostream>
      cout<<"Hello"s; 
    • 0b10: a binary number literal
      cout<<0b10; //you get 2;
    • complex 5i
      using namespace std::complex_literals;
      std::complex<double> z4 = 1.0 + 2i;   //ONLY double + 2i, no int!!
      std::cout << z4<< '\n';
    • std::chrono_literals: (C++14), Have to have using namespace std::chrono_literals
      • 5h, std::chrono::hours
      • 5min
      • 5s
      • E.g
        #include<chrono>
        int main(){
          using namespace std::chrono_literals; 
          cout<<1h/30min;       //you'll get 2
          std::this_thread::wait_for(40ms);
        }
  3. User Defined Literals: UDL

    long double operator"" _kg(long double x){return 1000*x;} 
    long double operator"" _g(long double x){return x;} 
    long double weight = 3.6_kg; 
    3.6_kg/2_g; 
    • only suffix form is supported for UDL (e.g, _kg)
    • UDL is treated as a call to the literal operator ""
⚠️ **GitHub.com Fallback** ⚠️