#include "pch.h"
#include "Cpp11.h"
#include <mutex>
#include <queue>
#include <regex>
#include <string>
#include <random>
#include <cassert>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
namespace MODERNCPP
{
// Simple move constructor
Cpp11::Cpp11(Cpp11&& arg) : member(std::move(arg.member)) // the expression "arg.member" is lvalue
{}
// Simple move assignment operator
Cpp11& Cpp11::operator=(Cpp11&& arg)
{
if (this != &arg)
member = std::move(arg.member);
return *this;
}
Cpp11::Cpp11(const std::initializer_list<int> &list) : // initialized via list initialization
Cpp11(0, 1) // possibly call delegating constructor
{
for (const auto &i : list)
m_vMap[count++] = i;
}
Cpp11& Cpp11::operator=(const std::initializer_list<int> &list)
{
count = 0;
for (const auto &i : list)
m_vMap[count++] = i;
return *this;
}
int& Cpp11::operator[](int index)
{
assert(index >= 0 && index < m_vMap.size());
return m_vMap[index];
}
void Cpp11::DoWork(void* pObj)
{
std::cout << "DoWork";
Cpp11* p = static_cast<Cpp11*>(pObj);
if (p)
{
p->DoWorkInternal();
}
}
void Cpp11::DoWorkInternal()
{
std::cout << "DoWorkInternal";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::thread Cpp11::DoWorkAsync(int n)
{
return std::thread([=] { DoWorkInternal(); });
}
void Cpp11::ForEachLoop()
{
// old way
for (std::vector<int>::iterator i = m_vMap.begin(); i != m_vMap.end(); i++)
std::cout << *i;
// auto
for (auto i = m_vMap.begin(); i != m_vMap.end(); i++)
std::cout << *i;
// auto foreach usinig reference (no copy)
for (const auto &i : m_vMap)
std::cout << i;
// foreach lambda
std::for_each(std::begin(m_vMap), std::end(m_vMap), [](auto i) {
std::cout << i;
});
std::cout << std::endl;
}
long Cpp11::EnumClass(WeekDay day)
{
return as_integer(day);
}
void Cpp11::Lambda()
{
// [firstPart](secondPart) TypeYouReturn{ BodyOfLambda}(acctualParameters);
/*
firstPart is used for variable scope which will be exploited inside the lambda function. You could use more variables if have a need for that.
Keep the following in mind when you are using this syntax for the [firstPart]:
[] it means that you will not provide anything to give to lambda.
[&] it is used to say that you have some references to mess with.
[=] it is used to make the copy.
[this] is used to the enclosing class.
secondPart is necessary for parameter list for nameless function but it could be left empty as well.
TypeYouReturn is used to register what type will be returned from your lambda.
BodyOfLambda is used for actions you wish to do, in here you will type some code that will be used to perform actions you are intended to apply in the body of this function.
actualParameters are used to provide input into lambda function.
*/
// generic lambda, operator() is a template with two parameters
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14); // ok
// generic lambda, operator() is a template with one parameter
auto vglambda = [](auto printer) {
return [=](auto&&... ts) // generic lambda, ts is a parameter pack
{
printer(std::forward<decltype(ts)>(ts)...);
return [=] { printer(ts...); }; // nullary lambda (takes no parameters)
};
};
auto p = vglambda([](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; });
auto q = p(1, 'a', 3.14); // outputs 1a3.14
q(); // outputs 1a3.14
// the context of the following lambda is the member function X::f
[=]()->int
{
return operator()(this->x + y); // X::operator()(this->x + (*this).y)
// this has type X*
};
std::cout << std::endl;
}
void Cpp11::StaticAssert()
{
// static_assert(evaluatedExpression, stringMessage);
//static_assert(sizeof(long long int) >= 16, "This is unexpected");
// Possible output:
// 1: error: static assertion failed : Swap requires copying
// 2: error : static assertion failed : Data Structure requires default - constructible elements
int a, b;
swap(a, b);
no_copy nc_a, nc_b;
//swap(nc_a, nc_b); // error 1
data_structure<int> ds_ok;
//data_structure<no_default> ds_error; // error 2
}
long Cpp11::PseudoNumberGenerator(int min, int max)
{
//normal_distribution // bell curve normal dist
uniform_int_distribution<int> num_range{ min, max }; // distribution that maps to the ints min..max
default_random_engine re {}; // the default engine
//std::cout << num_range(re); // x becomes a value in [1:6]
auto dice{ std::bind(num_range,re) }; // make a generator
auto d = dice(); // roll the dice: x becomes a value in [1:6]
std::cout << d << endl;
return d;
}
long Cpp11::RandomNumberGenerator(int min, int max)
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(min, max);
auto g = dis(gen);
std::cout << g << endl;
return g;
}
void Cpp11::UniquePtr()
{
std::unique_ptr<Cpp11> up(new Cpp11);
if (up && up->BaseMethod()) // use implicit cast to bool to ensure res contains a Resource
std::cout << *up;
}
std::tuple<int, double> Cpp11::ReturnTuple() // return a tuple that contains an int and a double
{
return std::make_tuple(5, 6.7); // std::make_tuple() as shortcut to make a tuple to return
}
void Cpp11::Tuple()
{
// tuple
std::tuple<int, double> s = ReturnTuple(); // get our tuple
std::cout << std::get<0>(s) << ' '
<< std::get<1>(s) << '\n'; // use std::get<n> to get the nth element of the tuple
// tie to tuple
int a;
double b;
std::tie(a, b) = ReturnTuple(); // put elements of tuple in variables a and b
std::cout << a << ' ' << b << '\n';
}
void Cpp11::ReferenceWrapper()
{
std::vector<std::reference_wrapper<Base>> v; // our vector is a vector of std::reference_wrapper wrapped Base (not Base&)
Base b; b.setValue(5);
Cpp11 d; d.setValue(6);
v.push_back(b); // add a Base object to our vector
v.push_back(d); // add a Derived object to our vector
// Print out all of the elements in our vector, use .get() to get our element from the wrapper
for (const auto& i : v)
std::cout << "Class = " << i.get().getName() << " Value = " << i.get().getValue() << "\n";
}
void Cpp11::InitializerList()
{
Cpp11 array{ 5, 4, 3, 2, 1 }; // initializer list
for (int count = 0; count < array.getLength(); ++count)
std::cout << array[count] << ' ';
array = { 1, 3, 5, 7, 9, 11 }; // calls assignment = init list
for (int count = 0; count < array.getLength(); ++count)
std::cout << array[count] << ' ';
std::cout << std::endl;
}
void Cpp11::VariadicTemplate()
{
long sum = adder(1, 2, 3, 8, 7);
std::string s1 = "x", s2 = "aa", s3 = "bb", s4 = "yy";
std::string ssum = adder(s1, s2, s3, s4);
std::cout << s1 << ssum << endl;
}
void Cpp11::UnorderedContainers()
{
//unordered_map
//unordered_set
//unordered_multimap
//unordered_multiset
// Iterate and print keys and values of unordered_map
for (const auto& n : u) {
std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
}
// Add two new entries to the unordered_map
u["BLACK"] = "#000000";
u["WHITE"] = "#FFFFFF";
// Output values by key
std::cout << "The HEX of color RED is:[" << u["RED"] << "]\n";
std::cout << "The HEX of color BLACK is:[" << u["BLACK"] << "]\n";
}
void Cpp11::RegularExpression()
{
std::string s = "Some people, when confronted with a problem, think "
"\"I know, I'll use regular expressions.\" "
"Now they have two problems.";
std::regex self_regex("REGULAR EXPRESSIONS",
std::regex_constants::ECMAScript | std::regex_constants::icase);
if (std::regex_search(s, self_regex)) {
std::cout << "Text contains the phrase 'regular expressions'\n";
}
std::regex word_regex("(\\S+)");
auto words_begin =
std::sregex_iterator(s.begin(), s.end(), word_regex);
auto words_end = std::sregex_iterator();
std::cout << "Found "
<< std::distance(words_begin, words_end)
<< " words\n";
const int N = 6;
std::cout << "Words longer than " << N << " characters:\n";
for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
std::smatch match = *i;
std::string match_str = match.str();
if (match_str.size() > N) {
std::cout << " " << match_str << '\n';
}
}
std::regex long_word_regex("(\\w{7,})");
std::string new_s = std::regex_replace(s, long_word_regex, "[$&]");
std::cout << new_s << '\n';
}
void Cpp11::ParallelThreads()
{
const size_t nloop = 11;
// Serial version
{
// Pre loop
std::cout << "serial:" << std::endl;
// loop over all items
for (int i = 0; i < nloop; i++)
{
// inner loop
{
const int j = i * i;
std::cout << j << std::endl;
}
}
// Post loop
std::cout << std::endl;
}
// Parallel version
// number of threads
const size_t nthreads = std::thread::hardware_concurrency();
{
// Pre loop
std::cout << "parallel (" << nthreads << " threads):" << std::endl;
std::vector<std::thread> threads(nthreads);
std::mutex critical;
for (int t = 0; t < nthreads; t++)
{
threads[t] = std::thread(std::bind(
[&](const int bi, const int ei, const int t)
{
// loop over all items
for (int i = bi; i < ei; i++)
{
// inner loop
{
const int j = i * i;
// (optional) make output critical
std::lock_guard<std::mutex> lock(critical);
std::cout << j << std::endl;
}
}
}, t*nloop / nthreads, (t + 1) == nthreads ? nloop : (t + 1)*nloop / nthreads, t));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& x) {x.join(); });
// Post loop
std::cout << std::endl;
}
}
void Cpp11::ProducerConsumer()
{
int c = 0;
bool done = false;
std::queue<int> goods;
thread producer([&]() {
for (int i = 0; i < 500; ++i) {
goods.push(i);
c++;
}
done = true;
});
thread consumer([&]() {
while (!done) {
while (!goods.empty()) {
goods.pop();
c--;
}
}
});
producer.join();
consumer.join();
cout << "Net: " << c << endl;
}
void Cpp11::DetachedThread()
{
unsigned int n = std::thread::hardware_concurrency();
std::cout << "Starting thread caller.\n";
std::cout << n << " concurrent threads are supported.\n";
std::thread t([this] { this->DoWorkInternal(); });
t.detach();
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Exiting thread caller.\n";
}
void Cpp11::VariableSizes()
{
std::cout << "bool:\t\t" << sizeof(bool) << " bytes" << std::endl;
std::cout << "char:\t\t" << sizeof(char) << " bytes" << std::endl;
std::cout << "wchar_t:\t" << sizeof(wchar_t) << " bytes" << std::endl;
std::cout << "char16_t:\t" << sizeof(char16_t) << " bytes" << std::endl; // C++11, may not be supported by your compiler
std::cout << "char32_t:\t" << sizeof(char32_t) << " bytes" << std::endl; // C++11, may not be supported by your compiler
std::cout << "short:\t\t" << sizeof(short) << " bytes" << std::endl;
std::cout << "int:\t\t" << sizeof(int) << " bytes" << std::endl;
std::cout << "long:\t\t" << sizeof(long) << " bytes" << std::endl;
std::cout << "long long:\t" << sizeof(long long) << " bytes" << std::endl; // C++11, may not be supported by your compiler
std::cout << "float:\t\t" << sizeof(float) << " bytes" << std::endl;
std::cout << "double:\t\t" << sizeof(double) << " bytes" << std::endl;
std::cout << "long double:\t" << sizeof(long double) << " bytes" << std::endl;
}
auto Cpp11::TrailingReturnType() const -> int
{
return 1;
}
void Cpp11::DeclType()
{
// C++ program to demonstrate working of auto and type inference
auto x = 4;
auto y = 3.37;
auto ptr = &x;
std::cout << typeid(x).name() << endl
<< typeid(y).name() << endl
<< typeid(ptr).name() << endl;
//int x = 5;
// j will be of type int : data type of x
decltype(x) j = x + 5;
std::cout << typeid(j).name();
// This call returns 3.44 of doubale type
std::cout << findMin(4, 3.44) << endl;
// This call returns 3 of int type
std::cout << findMin(5.4, 3) << endl;
}
std::ostream& operator<<(std::ostream& out, const Cpp11 &res)
{
out << "I am in Cpp11\n";
return out;
}
}