Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/clang-format-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ jobs:
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/[email protected]
with:
clang-format-version: '16'
clang-format-version: '19'
check-path: ${{ github.workspace }}
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ include_directories(shared)


##### subdirectories #####
set(DIRS week-W week-2 week-3 week-4 week-5 week-6 week-7 week-8 week-9 week-10 week-11)
set(DIRS week-W week-2 week-3 week-4 week-5 week-6 week-7 week-8 week-9 week-10 week-11 week-12)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
Expand Down
4 changes: 4 additions & 0 deletions week-12/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(DIRS task-11-01 task-11-03 task-11-06)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
3 changes: 3 additions & 0 deletions week-12/task-11-01/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
28 changes: 28 additions & 0 deletions week-12/task-11-01/include/self-pointed-function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <iostream>

namespace functions {

/**
* function returns itself.
*/
std::function<void(int& p)> do_it(int& param) {
param++;
static int counter = 1;
std::cout << "do it #" << counter << ": param = " << param << std::endl;
counter++;
return [](int& p) { do_it(p); };
}

void* foo();
template <auto F>
void* addressF() {
return reinterpret_cast<void*>(F);
}
/**
* function returns pointer to itself.
*/
void* foo() { return addressF<foo>(); }

} // namespace functions
1 change: 1 addition & 0 deletions week-12/task-11-01/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-11-01.cpp)
20 changes: 20 additions & 0 deletions week-12/task-11-01/test/test-11-01.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "gtest/gtest.h"
#include "self-pointed-function.hpp"

using functions::do_it;
using functions::foo;

TEST(FunctionReternsItself, Call) {
constexpr int initial = 42;
int var = initial; // NOLINT
auto do_it_again = do_it(var);
EXPECT_EQ(var, initial + 1);
do_it_again(var);
EXPECT_EQ(var, initial + 2);
}

TEST(SelfPointedFunction, Call) {
void* pfoo = foo();
auto func_ptr = reinterpret_cast<void* (*)()>(pfoo);
EXPECT_EQ(func_ptr(), foo());
}
3 changes: 3 additions & 0 deletions week-12/task-11-03/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
25 changes: 25 additions & 0 deletions week-12/task-11-03/include/factory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <functional>
#include <map>
#include <typeindex>
#include <variant>

namespace patterns {

template <typename... Ts>
class Factory {
public:
using creator_type = std::variant<std::function<Ts()>...>;
explicit Factory(std::function<Ts()>... args) : map_{{typeid(Ts), creator_type(args)}...} {}

template <typename T>
T create() const {
return std::get<std::function<T()>>(map_.find(typeid(T))->second)();
}

private:
std::unordered_map<std::type_index, std::variant<std::function<Ts()>...>> map_;
};

} // namespace patterns
1 change: 1 addition & 0 deletions week-12/task-11-03/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-11-03.cpp)
88 changes: 88 additions & 0 deletions week-12/task-11-03/test/test-11-03.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "factory.hpp"
#include "gtest/gtest.h"

using patterns::Factory;

struct Point {
int x, y;
bool operator==(const Point& other) const { return x == other.x && y == other.y; }
};

class Person {
public:
Person(std::string name, int age) : name_(std::move(name)), age_(age) {}
std::string getName() const { return name_; }
int getAge() const { return age_; }
bool operator==(const Person& other) const {
return name_ == other.name_ && age_ == other.age_;
}

private:
std::string name_;
int age_;
};

TEST(Factory, StandardTypes) {
constexpr int ret1 = 42;
constexpr double ret2 = 42.42;
const Factory<int, double> factory{[]() { return ret1; }, []() { return ret2; }};
EXPECT_EQ(factory.create<int>(), ret1);
EXPECT_FLOAT_EQ(factory.create<double>(), ret2);
}

TEST(Factory, CustomTypes) {
const Point point{10, 20};
const Person person{"Alice", 30};
const Factory<Point, Person> factory{[point]() { return point; },
[person]() { return person; }};
EXPECT_EQ(factory.create<Point>(), point);
EXPECT_EQ(factory.create<Person>(), person);
}

// @todo #15:30m/DEV find a way to check if a compilation error has occurred or not.
#ifdef TEST_COMPILE_ERROR
TEST(Factory, UnregisteredType) {
const Factory<int, double> factory{[]() { return 42; }, []() { return 3.14; }};
EXPECT_THROW(factory.create<std::string>(), std::runtime_error);
}

TEST(Factory, EmptyFactory) {
const Factory<int, double> factory{};
EXPECT_THROW(factory.create<int>(), std::runtime_error);
EXPECT_THROW(factory.create<double>(), std::runtime_error);
}
#endif

TEST(Factory, ComplexConstructors) {
const Factory<std::vector<int>, std::string> factory{
[]() { return std::vector<int>{1, 2, 3}; }, []() { return std::string("Hello, World!"); }};
const std::vector<int> expected_vector{1, 2, 3};
const std::string expected_string = "Hello, World!";
EXPECT_EQ(factory.create<std::vector<int>>(), expected_vector);
EXPECT_EQ(factory.create<std::string>(), expected_string);
}

TEST(Factory, SmartPointers) {
constexpr int ret1 = 42;
constexpr double ret2 = 3.14;
const Factory<std::unique_ptr<int>, std::shared_ptr<double>> factory{
[ret1]() { return std::make_unique<int>(ret1); },
[ret2]() { return std::make_shared<double>(ret2); }};
auto unique_ptr = factory.create<std::unique_ptr<int>>();
auto shared_ptr = factory.create<std::shared_ptr<double>>();
EXPECT_EQ(*unique_ptr, ret1);
EXPECT_DOUBLE_EQ(*shared_ptr, ret2);
}

TEST(Factory, OptionalTypes) {
const Factory<std::optional<int>, std::optional<std::string>> factory{
[]() { return std::optional<int>(42); }, // NOLINT
[]() { return std::optional<std::string>("Hello"); }};
EXPECT_EQ(factory.create<std::optional<int>>().value(), 42);
EXPECT_EQ(factory.create<std::optional<std::string>>().value(), "Hello");
}
3 changes: 3 additions & 0 deletions week-12/task-11-06/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
31 changes: 31 additions & 0 deletions week-12/task-11-06/include/circle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <numbers>

#include "ivisitor.hpp"
#include "shape.hpp"

namespace geometry2d {

class Circle : public Shape {
public:
static constexpr double pi = std::numbers::pi;

explicit Circle(double r) : radius_(r) {
if (radius_ <= 0) {
throw std::invalid_argument("Radius must be positive.");
}
}

double radius() const { return radius_; }

double perimeter() const override { return 2 * pi * radius_; }
double area() const override { return pi * radius_ * radius_; }

void visit_by(const IVisitor& visitor) const override { visitor.visit(*this); }

private:
double radius_;
};

} // namespace geometry2d
19 changes: 19 additions & 0 deletions week-12/task-11-06/include/ivisitor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

namespace geometry2d {

class Circle;
class Square;
class Triangle;
class Shape;

class IVisitor {
public:
virtual ~IVisitor() = default;

virtual void visit(const Circle& c) const = 0;
virtual void visit(const Square& s) const = 0;
virtual void visit(const Triangle& t) const = 0;
};

} // namespace geometry2d
36 changes: 36 additions & 0 deletions week-12/task-11-06/include/serializer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <iostream>

#include "circle.hpp"
#include "ivisitor.hpp"
#include "square.hpp"
#include "triangle.hpp"

namespace geometry2d {

class Serializer : public IVisitor {
public:
void visit(const Circle &c) const override {
std::cout << "Circle:" << std::endl;
std::cout << "\tradius: " << c.radius() << std::endl;
std::cout << "\t\tperimeter: " << c.perimeter() << std::endl;
std::cout << "\t\tarea: " << c.area() << std::endl;
}
void visit(const Square &s) const override {
std::cout << "Square:" << std::endl;
std::cout << "\tside: " << s.side() << std::endl;
std::cout << "\t\tperimeter: " << s.perimeter() << std::endl;
std::cout << "\t\tarea: " << s.area() << std::endl;
}
void visit(const Triangle &t) const override {
std::cout << "Triangle:" << std::endl;
std::cout << "\tside1: " << t.side1() << std::endl;
std::cout << "\tside2: " << t.side2() << std::endl;
std::cout << "\tside3: " << t.side3() << std::endl;
std::cout << "\t\tperimeter: " << t.perimeter() << std::endl;
std::cout << "\t\tarea: " << t.area() << std::endl;
}
};

} // namespace geometry2d
16 changes: 16 additions & 0 deletions week-12/task-11-06/include/shape.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "ivisitor.hpp"

namespace geometry2d {

class Shape {
public:
virtual ~Shape() = default;

virtual void visit_by(const IVisitor& visitor) const = 0;
virtual double perimeter() const = 0;
virtual double area() const = 0;
};

} // namespace geometry2d
27 changes: 27 additions & 0 deletions week-12/task-11-06/include/square.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include "ivisitor.hpp"
#include "shape.hpp"

namespace geometry2d {

class Square : public Shape {
public:
explicit Square(double s) : side_(s) {
if (side_ <= 0) {
throw std::invalid_argument("Side must be positive.");
}
}

double side() const { return side_; }

double perimeter() const override { return 4 * side_; }
double area() const override { return side_ * side_; }

void visit_by(const IVisitor& visitor) const override { visitor.visit(*this); }

private:
double side_;
};

} // namespace geometry2d
36 changes: 36 additions & 0 deletions week-12/task-11-06/include/triangle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <cmath>

#include "shape.hpp"

namespace geometry2d {

class Triangle : public Shape {
public:
Triangle(double s1, double s2, double s3) : side1_(s1), side2_(s2), side3_(s3) {
if (side1_ <= 0 || side2_ <= 0 || side3_ <= 0) {
throw std::invalid_argument("All sides must be positive.");
}
if (side1_ + side2_ <= side3_ || side1_ + side3_ <= side2_ || side2_ + side3_ <= side1_) {
throw std::invalid_argument("Invalid triangle sides.");
}
}

double side1() const { return side1_; }
double side2() const { return side2_; }
double side3() const { return side3_; }

double perimeter() const override { return side1_ + side2_ + side3_; }
double area() const override {
const double p = perimeter() / 2;
return std::sqrt(p * (p - side1_) * (p - side2_) * (p - side3_));
}

void visit_by(const IVisitor& visitor) const override { visitor.visit(*this); }

private:
double side1_, side2_, side3_;
};

} // namespace geometry2d
1 change: 1 addition & 0 deletions week-12/task-11-06/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-11-06.cpp)
Loading