Skip to content
Snippets Groups Projects
Commit 1e700fcb authored by Sandipan Mohanty's avatar Sandipan Mohanty
Browse files

Add day5 material

parent 6c8fbe5b
No related branches found
No related tags found
No related merge requests found
Showing
with 811 additions and 0 deletions
File added
#include <iostream>
#include <memory>
#include <vector>
#include <type_traits>
using namespace std::string_literals;
void func1(int x) { std::cout << "Integer = " << x << "\n"; }
void func1(double x) { std::cout << "Double = " << x << "\n"; }
void func1(std::string x) { std::cout << "std::string = \"" << x << "\"\n"; }
class PolyVal {
struct Internal {
virtual ~Internal() noexcept = default;
virtual auto clone() const -> std::unique_ptr<Internal> = 0;
virtual void func1_() const = 0;
};
template <class T>
struct Wrapped : public Internal {
Wrapped(T ex) : obj{ex} {}
~Wrapped() noexcept override {}
auto clone() const -> std::unique_ptr<Internal> override
{
return std::make_unique<Wrapped>(obj);
}
void func1_() const override
{
func1(obj);
}
T obj;
};
public:
template <class T>
PolyVal(const T& var) : ptr{ std::make_unique<Wrapped<T>>(var) } {}
PolyVal(const PolyVal& other) : ptr { other.ptr->clone() } {}
private:
friend void func1(const PolyVal& pv) { pv.ptr->func1_(); }
std::unique_ptr<Internal> ptr;
};
auto f(int i) -> PolyVal
{
if (i % 2 == 0)
return { 9 };
else
return { "Nine"s };
}
auto main() -> int
{
std::vector<PolyVal> v;
v.push_back(1);
v.push_back(2.0);
v.push_back("Green"s);
for (auto&& elem : v) {
func1(elem);
}
std::cout << "------------\n";
for (int i = 0; i < 6; ++i) {
std::cout << "Calling function with i = "
<< i << " and receiving PolyVal by value\n";
PolyVal X = f(i);
func1(X);
}
}
#include <iostream>
#include <string>
#include <concepts>
template <class T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
};
auto aggregate(Addable auto... args)
{
return (args + ...);
}
auto main() -> int
{
using namespace std::string_literals;
std::cout << "aggregate(1, 2, 3, 4, 5) = "
<< aggregate(1, 2, 3, 4, 5) << "\n";
std::cout << R"aw(aggregate("|-"s, "-|"s) = )aw"
<< aggregate("|-"s, "-|"s) << "\n";
}
#include <array>
#include <iostream>
#include <iomanip>
#include <cxx20format>
#include <ctre.hpp>
class Distance {
public:
enum class unit : unsigned { metre = 0U,
kilometre = 1U,
centimetre = 2U };
private:
static constexpr auto index(unit u) -> unsigned
{
return static_cast<unsigned>(u);
}
// The conv array has the factors you need to divide
// by to convert a value in a given unit to the
// internal representation, which is always in metres
static constexpr std::array conv { 1.0, 1.0e-3, 100.0 };
double val {}; // internal, always in metres
public:
Distance() = default;
Distance(const Distance&) = default;
Distance(Distance&&) noexcept = default;
auto operator=(const Distance&) -> Distance& = default;
auto operator=(Distance&&) noexcept -> Distance& = default;
Distance(double v, unit u)
: val { v / conv[index(u)] }
{
}
auto value(unit in_unit) const noexcept { return val * conv[index(in_unit)]; }
void value(double v, unit u) { val = v / conv[index(u)]; }
void str(std::string_view sv);
};
auto operator""_m(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::metre }; }
auto operator""_km(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::kilometre }; }
auto operator""_cm(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::centimetre }; }
auto operator<<(std::ostream& os, const Distance& d) -> std::ostream&
{
os << d.value(Distance::unit::metre) << "_m";
return os;
}
auto operator>>(std::istream& is, Distance& d) -> std::istream&
{
std::string val;
is >> std::quoted(val);
d.str(val);
return is;
}
auto main() -> int
{
Distance d { 4.0, Distance::unit::kilometre };
std::cout << d << "\n";
Distance c { 35.4_cm };
std::cout << c << "\n";
std::cout << "Enter distance: ";
std::cin >> d;
std::cout << "That's " << d << "\n";
}
void Distance::str(std::string_view diststr)
{
static constexpr ctll::fixed_string trx {
R"(^(-?[0-9]*\.?[0-9]+)(_|[ ]*)(m|metre|metres|cm|centimetre|centimetres|km|kilometre|kilometres)$)"
};
if (auto m = ctre::match<trx>(diststr); m) {
auto numstr = m.get<1>().to_string();
auto num = std::stod(numstr);
auto ustr = m.get<3>().to_view();
if (ustr == "m" or ustr == "metre" or ustr == "metres") {
value(num, unit::metre);
} else if (ustr == "cm" or ustr == "centimetre" or ustr == "centimetres") {
value(num, unit::centimetre);
} else if (ustr == "km" or ustr == "kilometre" or ustr == "kilometres") {
value(num, unit::kilometre);
}
} else {
throw std::runtime_error(fmt::format(R"(Bad value "{}" for distance!)", diststr));
}
}
#include <cxx20format>
#include <iostream>
#include <string>
#include <tuple>
auto main() -> int
{
using namespace std;
using namespace std::string_literals;
for (auto i = 0UL; i < 110UL; ++i) {
std::cout << fmt::format(
"i = {0:010d}, E_tot = {2:16.12f}, E_hb = {1:8.4f}\n",
i, exp(cos(1.0 * i)), exp(sin(1.0 * i))
);
}
}
cmake_minimum_required(VERSION 3.10)
project(polymorphic_w_any CXX)
set(CMAKE_CXX_EXTENSIONS OFF)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set(Headers Point.hh Polygon.hh Triangle.hh Circle.hh)
add_executable(${PROJECT_NAME} Point.cc Triangle.cc Circle.cc main.cc ${Headers})
#include "Circle.hh"
constexpr double pi = 3.141592653589793;
Circle::Circle(double rad, const Point& p)
: r{ rad }
, c{ p }
{
}
double Circle::area() const
{
return pi * r * r;
}
double Circle::perimeter() const
{
return 2 * pi * r;
}
void Circle::rotate(double phi) { phi = 0; }
void Circle::translate(Point p)
{
c += p;
}
#ifndef Circle_HH
#define Circle_HH
#include "Point.hh"
#include <string>
class Circle {
public:
Circle() = default;
Circle(double rad, const Point& p);
Circle(const Circle& cir) = default;
Circle(Circle&& cir) = default;
Circle& operator=(const Circle& cir) = default;
Circle& operator=(Circle&& cir) = default;
std::string name() const { return "Circle"; }
void rotate(double phi);
void translate(Point p);
double area() const;
double perimeter() const;
inline double circumference() const { return perimeter(); }
private:
double r{ 1.0 };
Point c{}; // Use default constructor of class Point to create c
};
#endif
#include "Point.hh"
#include <iostream>
Point::Point(double x, double y)
: X{ x }
, Y{ y }
{
}
Point& Point::operator+=(const Point& p)
{
X += p.X;
Y += p.Y;
return *this;
}
Point& Point::operator-=(const Point& p)
{
X -= p.X;
Y -= p.Y;
return *this;
}
Point Point::operator+(const Point& p) const
{
return { X + p.X, Y + p.Y };
}
Point Point::operator-(const Point& p) const
{
return { X - p.X, Y - p.Y };
}
double Point::operator*(const Point& p) const
{
return (X * p.X + Y * p.Y);
}
Point Point::operator*(double f) const
{
return { f * X, f * Y };
}
Point operator*(double f, const Point& p)
{
return { f * p.X, f * p.Y };
}
std::ostream& operator<<(std::ostream& os, const Point& p)
{
os << "(" << p.X << ", " << p.Y << ")";
return os;
}
#ifndef Point_HH
#define Point_HH
class ostream;
struct Point {
double X = 0, Y = 0;
Point() = default;
Point(const Point&) = default;
Point(Point&&) = default;
Point& operator=(const Point& p) = default;
Point& operator=(Point&& p) = default;
Point(double x, double y);
Point& operator+=(const Point& p);
Point& operator-=(const Point& p);
Point operator+(const Point& p) const;
Point operator-(const Point& p) const;
double operator*(const Point& p) const;
Point operator*(double f) const;
};
Point operator*(double f, const Point& p);
ostream& operator<<(ostream& os, const Point& p);
#endif
#ifndef Polygon_HH
#define Polygon_HH
#include "Point.hh"
#include <array>
#include <cmath>
#include <string>
template <unsigned int NV>
class Polygon {
static_assert(NV > 2, "Can't have polygon with less than 3 sides");
public:
Polygon() = default;
Polygon(const Polygon&) = default;
Polygon(Polygon&&) = default;
Polygon& operator=(const Polygon& pg) = default;
Polygon& operator=(Polygon&&) = default;
constexpr auto n_vertexes() const { return NV; }
std::string name() const { return "Polygon<" + std::to_string(NV) + ">"; }
double perimeter() const
{
double ans = 0;
for (size_t i = 1; i < vertex.size(); ++i) {
ans += sqrt((vertex[i] - vertex[i - 1]) * (vertex[i] - vertex[i - 1]));
}
ans += sqrt((vertex.front() - vertex.back()) * (vertex.front() - vertex.back()));
return ans;
}
void translate(Point p)
{
for (auto& pt : vertex)
pt += p;
}
void rotate(double phi)
{
Point center;
for (auto pt : vertex)
center += pt;
center = (1.0 / NV) * center;
double ct = cos(phi), st = sin(phi);
for (auto& pt : vertex) {
auto rel = pt - center;
pt = center + Point(ct * rel.X + st * rel.Y, -st * rel.X + ct * rel.Y);
}
}
protected:
std::array<Point, NV> vertex;
};
#endif
#include "Triangle.hh"
#include <cmath>
// A "static" function in a source file (not a static member function of a class)
// is meant to be visible only in the same translation unit, most often just that
// source file.
static inline double sqr(Point p) { return p * p; }
Triangle::Triangle(Point p1, Point p2, Point p3)
{
vertex[0] = p1;
vertex[1] = p2;
vertex[2] = p3;
}
double Triangle::area() const
{
double s = 0.5 * perimeter();
double a = sqrt(sqr(vertex[0] - vertex[1]));
double b = sqrt(sqr(vertex[0] - vertex[2]));
double c = sqrt(sqr(vertex[1] - vertex[2]));
return sqrt(s * (s - a) * (s - b) * (s - c));
}
#include "Polygon.hh"
class Triangle : public Polygon<3> {
public:
using Polygon<3>::Polygon;
using Polygon<3>::operator=;
Triangle(Point p1, Point p2, Point p3);
double area() const;
};
#include "Circle.hh"
#include "Triangle.hh"
#include <chrono>
#include <random>
#include <iostream>
#include <vector>
#include <any>
constexpr auto N = 100000ul;
std::mt19937_64 engine;
std::discrete_distribution sel{ 0.5, 0.5 };
std::exponential_distribution length{ 1.0 };
using element_type = std::any;
auto name(const std::vector<element_type>& v, size_t i)
{
if (v[i].type() == typeid(Triangle)) {
return std::any_cast<Triangle>(v[i]).name();
} else {
return std::any_cast<Circle>(v[i]).name();
}
}
auto area(const std::vector<element_type>& v, size_t i)
{
if (v[i].type() == typeid(Triangle)) {
return std::any_cast<Triangle>(v[i]).area();
} else {
return std::any_cast<Circle>(v[i]).area();
}
}
void construct_objects(std::vector<element_type>& v)
{
for (auto i = 0ul; i < N; ++i) {
auto isel = sel(engine);
switch (isel) {
case 0: {
auto radius = length(engine);
auto centrepos = Point(length(engine), length(engine));
v.emplace_back(std::in_place_type_t<Circle>{}, radius, centrepos);
break;
}
case 1: {
auto v1 = Point(length(engine), length(engine));
auto v2 = Point(length(engine), length(engine));
auto v3 = Point(length(engine), length(engine));
v.emplace_back(std::in_place_type_t<Triangle>{}, v1, v2, v3);
break;
}
};
}
}
void calc_area_all(const std::vector<element_type>& v)
{
auto max_loc = 0ul;
auto max_area = 0.;
for (size_t i = 0; i < v.size(); ++i) {
auto ar = area(v, i);
if (i < 5) {
std::cout << i << ": " << name(v, i) << " with area "
<< ar << "\n";
}
if (ar > max_area) {
max_loc = i;
}
}
std::cout << "Largest object: \n";
auto nm = name(v, max_loc);
auto ar = area(v, max_loc);
std::cout << "Name : " << nm << ", area = " << ar << "\n";
}
int main()
{
std::vector<element_type> shapes;
shapes.reserve(N);
auto t0 = std::chrono::steady_clock::now();
construct_objects(shapes);
auto t1 = std::chrono::steady_clock::now();
calc_area_all(shapes);
auto t2 = std::chrono::steady_clock::now();
std::cout << "Object creation time for " << N << " objects, "
<< std::chrono::duration<double>(t1 - t0).count() << "\n"
<< "Area evaluation time for " << N << " objects, "
<< std::chrono::duration<double>(t2 - t1).count() << "\n";
}
cmake_minimum_required(VERSION 3.18)
project(polymorphic_w_any CXX)
set(CMAKE_CXX_EXTENSIONS OFF)
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-fmodules HAS_FMODULES)
if (HAS_FMODULES)
set(COMPILE_FLAGS -fmodules ${COMPILE_FLAGS})
else()
check_cxx_compiler_flag(-fmodules-ts HAS_FMODULES_TS)
if (HAS_FMODULES_TS)
set(COMPILE_FLAGS -fmodules-ts ${COMPILE_FLAGS})
else()
message(FATAL_ERROR "This compiler does not have either of the options -fmodules or -fmodules-ts!")
endif()
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if (NOT CMI_CACHE)
set(CMI_CACHE ${PROJECT_BINARY_DIR}/pcm.cache)
endif()
set(CMI_EXT ".pcm")
set(COMPILE_FLAGS ${COMPILE_FLAGS} -std=c++20 -stdlib=libc++ -fbuiltin-module-map -fprebuilt-module-path=${CMI_CACHE})
set(MIFC_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} --precompile -xc++-module)
set(MIMP_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} -xc++ -c)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if (NOT CMI_CACHE)
set(CMI_CACHE ${PROJECT_BINARY_DIR}/gcm.cache)
endif()
set(CMI_EXT ".gcm")
message(STATUS "Generating standard library header units.")
execute_process(COMMAND ${PROJECT_SOURCE_DIR}/make_gcm_cache.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
OUTPUT_VARIABLE CMI_CACHE
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Done.")
set(MIFC_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} -std=c++20 -c -xc++)
set(MIMP_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS})
else()
message(FATAL_ERROR "Unsupported compiler ...")
endif()
file(MAKE_DIRECTORY ${CMI_CACHE})
set(ADDITIONAL_CLEAN_FILES ${CMI_CACHE})
function(module_interface out_var)
set(result)
foreach(in_f ${ARGN})
file(RELATIVE_PATH out_f ${CMAKE_CURRENT_SOURCE_DIR} ${in_f})
string(REGEX REPLACE "[.]ixx$" ${CMI_EXT} out_f ${out_f})
set(out_f "${CMI_CACHE}/${out_f}")
add_custom_command(OUTPUT ${out_f}
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -o ${out_f} ${MIFC_BUILD_FLAGS} ${in_f}
DEPENDS ${in_f}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Creating module interface file ${out_f}"
VERBATIM
)
list(APPEND result ${out_f})
endforeach()
set(${out_var} "${result}" PARENT_SCOPE)
endfunction()
module_interface(mod_Point ${CMAKE_CURRENT_SOURCE_DIR}/Point.ixx)
module_interface(mod_Circle ${CMAKE_CURRENT_SOURCE_DIR}/Circle.ixx)
module_interface(mod_Polygon ${CMAKE_CURRENT_SOURCE_DIR}/Polygon.ixx)
module_interface(mod_Triangle ${CMAKE_CURRENT_SOURCE_DIR}/Triangle.ixx)
set(mods ${mod_Point} ${mod_Circle} ${mod_Polygon} ${mod_Triangle})
add_library(shapes
${mods}
Point.ixx
Circle.ixx
Polygon.ixx
Triangle.ixx
)
target_compile_options(shapes PRIVATE ${MIMP_BUILD_FLAGS})
add_executable(${PROJECT_NAME} main.cc)
target_link_libraries(${PROJECT_NAME} shapes)
target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_FLAGS})
module;
import <string>;
import <numbers>;
import Point;
export module Circle;
using std::numbers::pi;
export class Circle {
public:
Circle() = default;
Circle(double rad, const Point& p);
Circle(const Circle& cir) = default;
Circle(Circle&& cir) = default;
Circle& operator=(const Circle& cir) = default;
Circle& operator=(Circle&& cir) = default;
std::string name() const { return "Circle"; }
void rotate(double phi);
void translate(Point p);
double area() const;
double perimeter() const;
inline double circumference() const { return perimeter(); }
private:
double r{ 1.0 };
Point c{}; // Use default constructor of class Point to create c
};
Circle::Circle(double rad, const Point& p)
: r{ rad }
, c{ p }
{
}
double Circle::area() const
{
return pi * r * r;
}
double Circle::perimeter() const
{
return 2 * pi * r;
}
void Circle::rotate(double phi) { phi = 0; }
void Circle::translate(Point p)
{
c += p;
}
module;
import <iostream>;
export module Point;
export struct Point {
double X = 0, Y = 0;
Point() = default;
Point(const Point&) = default;
Point(Point&&) = default;
Point& operator=(const Point& p) = default;
Point& operator=(Point&& p) = default;
Point(double x, double y);
Point& operator+=(const Point& p);
Point& operator-=(const Point& p);
Point operator+(const Point& p) const;
Point operator-(const Point& p) const;
double operator*(const Point& p) const;
Point operator*(double f) const;
};
export auto operator*(double f, const Point& p) -> Point;
export auto operator<<(std::ostream& os, const Point& p) -> std::ostream&;
Point::Point(double x, double y)
: X{ x }
, Y{ y }
{
}
Point& Point::operator+=(const Point& p)
{
X += p.X;
Y += p.Y;
return *this;
}
Point& Point::operator-=(const Point& p)
{
X -= p.X;
Y -= p.Y;
return *this;
}
Point Point::operator+(const Point& p) const
{
return { X + p.X, Y + p.Y };
}
Point Point::operator-(const Point& p) const
{
return { X - p.X, Y - p.Y };
}
double Point::operator*(const Point& p) const
{
return (X * p.X + Y * p.Y);
}
Point Point::operator*(double f) const
{
return { f * X, f * Y };
}
Point operator*(double f, const Point& p)
{
return { f * p.X, f * p.Y };
}
std::ostream& operator<<(std::ostream& os, const Point& p)
{
os << "(" << p.X << ", " << p.Y << ")";
return os;
}
module;
import <cmath>;
import <array>;
import <string>;
export module Polygon;
import Point;
export template <unsigned int NV>
class Polygon {
static_assert(NV > 2, "Can't have polygon with less than 3 sides");
public:
Polygon() = default;
Polygon(const Polygon&) = default;
Polygon(Polygon&&) = default;
Polygon& operator=(const Polygon& pg) = default;
Polygon& operator=(Polygon&&) = default;
constexpr auto n_vertexes() const { return NV; }
inline std::string name() const { return "Polygon<" + std::to_string(NV) + ">"; }
double perimeter() const
{
double ans = 0;
for (size_t i = 1; i < vertex.size(); ++i) {
ans += sqrt((vertex[i] - vertex[i - 1]) * (vertex[i] - vertex[i - 1]));
}
ans += sqrt((vertex.front() - vertex.back()) * (vertex.front() - vertex.back()));
return ans;
}
void translate(Point p)
{
for (auto& pt : vertex)
pt += p;
}
void rotate(double phi)
{
Point center;
for (auto pt : vertex)
center += pt;
center = (1.0 / NV) * center;
double ct = cos(phi), st = sin(phi);
for (auto& pt : vertex) {
auto rel = pt - center;
pt = center + Point(ct * rel.X + st * rel.Y, -st * rel.X + ct * rel.Y);
}
}
protected:
std::array<Point, NV> vertex;
};
module;
import <array>;
import <cmath>;
export module Triangle;
import Polygon;
import Point;
export class Triangle : public Polygon<3U> {
public:
using Polygon<3U>::Polygon;
using Polygon<3U>::operator=;
using Polygon<3U>::name;
Triangle(Point p1, Point p2, Point p3);
double area() const;
};
// not exported
inline double sqr(Point p) { return p * p; }
Triangle::Triangle(Point p1, Point p2, Point p3)
{
vertex[0] = p1;
vertex[1] = p2;
vertex[2] = p3;
}
double Triangle::area() const
{
double s = 0.5 * perimeter();
double a = sqrt(sqr(vertex[0] - vertex[1]));
double b = sqrt(sqr(vertex[0] - vertex[2]));
double c = sqrt(sqr(vertex[1] - vertex[2]));
return sqrt(s * (s - a) * (s - b) * (s - c));
}
for m in Point Circle Polygon Triangle; do
echo "Generating CMI for $m"
clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. --precompile -xc++-module $m.ixx
done
for m in Point Circle Polygon Triangle; do
echo "Generating object file for $m"
clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. -xc++ -c $m.ixx
done
echo "Compiling main.cc -> a.clg"
clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. -o a.clg main.cc Point.o Circle.o Polygon.o Triangle.o
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment