Created
March 16, 2023 18:17
-
-
Save vladiant/9e5a13f1590568e6576faada88df8793 to your computer and use it in GitHub Desktop.
"Clean" Code, Horrible Performance and the forgotten variant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://www.reddit.com/r/cpp/comments/11rzncu/clean_code_horrible_performance_and_the_forgotten/ | |
// https://quick-bench.com/q/mW30pqwTvtWZ-aT6COu1oiUycYc | |
#include <cmath> | |
#include <cstdlib> | |
#include <cstddef> | |
#include <ctime> | |
#include <memory> | |
#include <variant> | |
#include <vector> | |
namespace utils { | |
inline float random_float() { | |
return static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX); | |
} | |
inline constexpr float pi = 3.14159265358979323846f; | |
} // namespace utils | |
namespace clean { | |
class shape_base { | |
public: | |
shape_base() {} | |
virtual float Area() const = 0; | |
}; | |
class square : public shape_base { | |
public: | |
square(float SideInit) : Side(SideInit) {} | |
virtual float Area() const { return Side * Side; } | |
private: | |
float Side; | |
}; | |
class rectangle : public shape_base { | |
public: | |
rectangle(float WidthInit, float HeightInit) | |
: Width(WidthInit), Height(HeightInit) {} | |
virtual float Area() const { return Width * Height; } | |
private: | |
float Width, Height; | |
}; | |
class triangle : public shape_base { | |
public: | |
triangle(float BaseInit, float HeightInit) | |
: Base(BaseInit), Height(HeightInit) {} | |
virtual float Area() const { return 0.5f * Base * Height; } | |
private: | |
float Base, Height; | |
}; | |
class circle : public shape_base { | |
public: | |
circle(float RadiusInit) : Radius(RadiusInit) {} | |
virtual float Area() const { return utils::pi * Radius * Radius; } | |
private: | |
float Radius; | |
}; | |
inline std::vector<std::unique_ptr<shape_base>> | |
shape_builder(std::size_t count) { | |
std::srand(std::time(nullptr)); | |
std::vector<std::unique_ptr<shape_base>> shapes; | |
shapes.reserve(count); | |
for (std::size_t i = 0; i < count; i++) { | |
switch (std::rand() % 4) { | |
case 0: | |
shapes.push_back(std::make_unique<square>(utils::random_float())); | |
break; | |
case 1: | |
shapes.push_back(std::make_unique<rectangle>(utils::random_float(), | |
utils::random_float())); | |
break; | |
case 2: | |
shapes.push_back(std::make_unique<triangle>(utils::random_float(), | |
utils::random_float())); | |
break; | |
case 3: | |
shapes.push_back(std::make_unique<circle>(utils::random_float())); | |
break; | |
} | |
} | |
return shapes; | |
} | |
inline float | |
total_area(const std::vector<std::unique_ptr<shape_base>> &shapes) { | |
float total_area{}; | |
for (const auto &shape : shapes) { | |
total_area += shape->Area(); | |
} | |
return total_area; | |
} | |
} // namespace clean | |
namespace switchcase { | |
enum shape_type { | |
Shape_Square, | |
Shape_Rectangle, | |
Shape_Triangle, | |
Shape_Circle, | |
Shape_Count, | |
}; | |
struct shape_union { | |
shape_type Type; | |
float Width; | |
float Height; | |
}; | |
inline float GetAreaSwitch(shape_union Shape) { | |
float Result = 0.0f; | |
switch (Shape.Type) { | |
case Shape_Square: { | |
Result = Shape.Width * Shape.Width; | |
} break; | |
case Shape_Rectangle: { | |
Result = Shape.Width * Shape.Height; | |
} break; | |
case Shape_Triangle: { | |
Result = 0.5f * Shape.Width * Shape.Height; | |
} break; | |
case Shape_Circle: { | |
Result = utils::pi * Shape.Width * Shape.Width; | |
} break; | |
case Shape_Count: { | |
} break; | |
} | |
return Result; | |
} | |
inline std::vector<shape_union> shape_builder(std::size_t count) { | |
std::srand(std::time(nullptr)); | |
std::vector<shape_union> shapes; | |
shapes.reserve(count); | |
for (std::size_t i = 0; i < count; i++) { | |
shapes.push_back(shape_union{static_cast<shape_type>(std::rand() % 4), | |
utils::random_float(), utils::random_float()}); | |
} | |
return shapes; | |
} | |
inline float total_area(const std::vector<shape_union> &shapes) { | |
float total_area{}; | |
for (const auto &shape : shapes) { | |
total_area += GetAreaSwitch(shape); | |
} | |
return total_area; | |
} | |
} // namespace switchcase | |
namespace variant { | |
class square { | |
public: | |
square(float SideInit) : Side(SideInit) {} | |
float Area() const { return Side * Side; } | |
private: | |
float Side; | |
}; | |
class rectangle { | |
public: | |
rectangle(float WidthInit, float HeightInit) | |
: Width(WidthInit), Height(HeightInit) {} | |
float Area() const { return Width * Height; } | |
private: | |
float Width, Height; | |
}; | |
class triangle { | |
public: | |
triangle(float BaseInit, float HeightInit) | |
: Base(BaseInit), Height(HeightInit) {} | |
float Area() const { return 0.5f * Base * Height; } | |
private: | |
float Base, Height; | |
}; | |
class circle { | |
public: | |
circle(float RadiusInit) : Radius(RadiusInit) {} | |
float Area() const { return utils::pi * Radius * Radius; } | |
private: | |
float Radius; | |
}; | |
using any_shape = std::variant<square, rectangle, triangle, circle>; | |
inline std::vector<any_shape> shape_builder(std::size_t count) { | |
std::srand(std::time(nullptr)); | |
std::vector<any_shape> shapes; | |
shapes.reserve(count); | |
for (std::size_t i = 0; i < count; i++) { | |
switch (std::rand() % 4) { | |
case 0: | |
shapes.push_back(square(utils::random_float())); | |
break; | |
case 1: | |
shapes.push_back(rectangle(utils::random_float(), utils::random_float())); | |
break; | |
case 2: | |
shapes.push_back(triangle(utils::random_float(), utils::random_float())); | |
break; | |
case 3: | |
shapes.push_back(circle(utils::random_float())); | |
break; | |
} | |
} | |
return shapes; | |
} | |
inline float shape_area(const any_shape &s) { | |
return std::visit([](const auto &shape) { return shape.Area(); }, s); | |
} | |
inline float total_area(const std::vector<any_shape> &shapes) { | |
float total_area{}; | |
for (const auto &shape : shapes) { | |
total_area += shape_area(shape); | |
} | |
return total_area; | |
} | |
} // namespace variant | |
inline constexpr std::size_t shape_count = 1000; | |
static void clean_code(benchmark::State &state) { | |
const auto shapes = clean::shape_builder(shape_count); | |
for (auto _ : state) { | |
benchmark::DoNotOptimize(clean::total_area(shapes)); | |
} | |
} | |
static void switch_case(benchmark::State &state) { | |
const auto shapes = switchcase::shape_builder(shape_count); | |
for (auto _ : state) { | |
benchmark::DoNotOptimize(switchcase::total_area(shapes)); | |
} | |
} | |
static void std_variant(benchmark::State &state) { | |
const auto shapes = variant::shape_builder(shape_count); | |
for (auto _ : state) { | |
benchmark::DoNotOptimize(variant::total_area(shapes)); | |
} | |
} | |
BENCHMARK(clean_code); | |
BENCHMARK(switch_case); | |
BENCHMARK(std_variant); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment