The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

MODE: INLINE
#include <cmath>
#include <iostream>
struct PointRecipe12 {
double x;
double y;
};
double distance(const PointRecipe12& pt_a, const PointRecipe12& pt_b) {
auto dx = pt_a.x - pt_a.x;
auto dy = pt_a.y - pt_b.y;
return std::sqrt(dx * dx + dy * dy);
}
struct StatisticsRecipe12 {
StatisticsRecipe12(const PointRecipe12& interest_, const std::vector<PointRecipe12>& points_): interest{interest_}, points{points_} {
if(points.empty()) throw std::runtime_error("points cannot be empty");
}
const PointRecipe12& nearest() const {
return select([](const double& prev_dist, const double& new_dist) { return new_dist < prev_dist; } );
}
const PointRecipe12& farest() const {
return select([](const double& prev_dist, const double& new_dist) { return new_dist > prev_dist; } );
}
private:
template<typename F>
const PointRecipe12& select(F&& fn) const {
const PointRecipe12* pt = &points.front();
auto best_distance = distance(interest, *pt);
for(auto it = points.cbegin() + 1; it != points.cend(); ++it) {
auto new_distance = distance(interest, *it);
if(fn(best_distance, new_distance)) {
pt = &*it;
best_distance = new_distance;
}
}
return *pt;
}
const PointRecipe12& interest;
const std::vector<PointRecipe12>& points;
};
namespace xs {
template <>
struct Typemap<PointRecipe12*> : TypemapObject<PointRecipe12*, PointRecipe12*, ObjectTypePtr, ObjectStorageMG> {
static std::string package () { return "MyTest::Cookbook::PointRecipe12"; }
};
template <>
struct Typemap<StatisticsRecipe12*> : TypemapObject<StatisticsRecipe12*, StatisticsRecipe12*, ObjectTypePtr, ObjectStorageMG> {
static std::string package () { return "MyTest::Cookbook::StatisticsRecipe12"; }
};
}
static xs::Sv::payload_marker_t payload_marker_12;
struct StatisticsRecipe12_payload {
PointRecipe12 interest;
std::vector<PointRecipe12> points;
~StatisticsRecipe12_payload() { std::cout << "~StatisticsRecipe12_payload\n"; }
};
static int payload_marker_IntersectionFinderAdder_free(pTHX_ SV*, MAGIC* mg) {
if (mg->mg_virtual == &payload_marker_12) {
auto* payload = static_cast<StatisticsRecipe12_payload*>((void*)mg->mg_ptr);
delete payload;
}
return 0;
}
MODULE = MyTest::Cookbook PACKAGE = MyTest::Cookbook::PointRecipe12
PROTOTYPES: DISABLE
double PointRecipe12::x(SV* new_val = nullptr) : ALIAS(y = 1) {
double* val = nullptr;
switch(ix) {
case 1: val = &THIS->y; break;
default: val = &THIS->x; break;
}
if (new_val) {
*val = SvNV(new_val);
}
RETVAL = *val;
}
PointRecipe12* PointRecipe12::new(double x = 0, double y = 0) {
RETVAL = new PointRecipe12{x, y};
}
MODULE = MyTest::Cookbook PACKAGE = MyTest::Cookbook::StatisticsRecipe12
PROTOTYPES: DISABLE
PointRecipe12* StatisticsRecipe12::nearest() {
RETVAL = new PointRecipe12(THIS->nearest());
}
PointRecipe12* StatisticsRecipe12::farest() {
RETVAL = new PointRecipe12(THIS->farest());
}
Sv StatisticsRecipe12::new(PointRecipe12* interest, Array pts) {
using payload_ptr_t = std::unique_ptr<StatisticsRecipe12_payload>;
using stats_ptr_t = std::unique_ptr<StatisticsRecipe12>;
std::vector<PointRecipe12> points;
for(auto it: pts) {
points.push_back(*(xs::in<PointRecipe12*>(it)));
}
// better to use std::make_unique from C++ 14, if available.
auto payload_holder = payload_ptr_t{new StatisticsRecipe12_payload{ *interest, std::move(points) }};
auto self_holder = stats_ptr_t{new StatisticsRecipe12{ payload_holder->interest, payload_holder->points }};
Object self = xs::out(self_holder.get(), CLASS);
self.payload_attach((void*)payload_holder.get(), &payload_marker_12);
payload_holder.release();
self_holder.release();
RETVAL = self.ref();
}
BOOT {
payload_marker_12.svt_free = payload_marker_IntersectionFinderAdder_free;
}