Skip to content

Instantly share code, notes, and snippets.

@alexcohn
Last active August 24, 2019 09:47
Show Gist options
  • Save alexcohn/e38642f772d7bbfa62baaca0fd1ad0da to your computer and use it in GitHub Desktop.
Save alexcohn/e38642f772d7bbfa62baaca0fd1ad0da to your computer and use it in GitHub Desktop.
#include <iostream>
enum SumOfWeights {
N
};
template<class T>
class is_time_point {
template<typename U> static auto test(U const* u) -> decltype(u->time_since_epoch(), std::true_type());
template<typename> static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(new T()))::value;
};
template<class T>
class has_x {
template<typename U> static auto test(U const* u) -> decltype(u->x, std::true_type());
template<typename> static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(new T()))::value;
};
template<class T>
class Combination {
double sumOfWeights;
T accum;
Combination() = delete;
public:
Combination(Combination<T> const &) = default;
Combination(T const &t) {
sumOfWeights = 1;
accum = t;
}
T affineCombination() const {
if constexpr(is_time_point<T>::value) {
auto d = accum.time_since_epoch();
std::cerr << "{ time_point " << d.count() << "/" << sumOfWeights << " } " << std::flush;
d /= sumOfWeights;
return T(d);
}
else if constexpr(has_x<T>::value) {
T ret;
typedef decltype(ret.x) V;
std::cerr << "{ double[" << sizeof(T) / sizeof(V) << "]/" << sumOfWeights << " } " << std::flush;
auto accum_ptr = reinterpret_cast<const V *>(&accum);
auto ret_ptr = reinterpret_cast<V *>(&ret);
for (int idx = 0; idx < sizeof(T) / sizeof(V); idx++) {
ret_ptr[idx] = accum_ptr[idx] / sumOfWeights;
}
return ret;
}
}
T operator/(SumOfWeights) const {
std::cerr << "{ operator/(SumOfWeights) } " << std::flush;
return affineCombination();
}
T operator/(double w) const {
std::cerr << "{ operator/(" << w << ") } " << std::flush;
// if (w == 0) {
// auto t = 1/(int)w;
// return (t*accum)/w;
// }
return affineCombination();
}
Combination<T> operator+=(T const& other) {
return operator+=(Combination<T>(other));
}
Combination<T> operator+(Combination<T> const& other) const {
Combination<T> ret = *this;
return (ret += other);
}
Combination<T> operator*(double weight) const {
Combination<T> ret = *this;
return (ret *= weight);
}
Combination<T> operator+=(Combination<T> const& other) {
sumOfWeights += other.sumOfWeights;
if constexpr(is_time_point<T>::value) {
accum += other.accum.time_since_epoch();
} else {
auto accum_ptr = reinterpret_cast<double *>(&accum);
auto two_ptr = reinterpret_cast<const double *>(&other.accum);
for (int idx = 0; idx < sizeof(T) / sizeof(double); idx++) {
accum_ptr[idx] += two_ptr[idx];
}
}
return *this;
};
Combination<T> operator*=(double weight) {
sumOfWeights *= weight;
if constexpr(is_time_point<T>::value) {
auto cnt = accum.time_since_epoch();
accum = weight;
} else {
auto accum_ptr = reinterpret_cast<double *>(&accum);
for (int idx = 0; idx < sizeof(T) / sizeof(double); idx++) {
accum_ptr[idx] *= weight;
}
}
return *this;
};
};
template <class T>
Combination<T> operator+(const T& one, const T& two) {
Combination<T> ret(one);
return ret += two;
};
template <class T>
Combination<T> operator*(double weight, const T& t) {
Combination<T> ret(t);
return ret *= weight;
};
struct Point {
double x;
double y;
};
//Point operator + (const Point& a, const Point& b) // copied from OpenCV, but cannot stay: we can't override this for our purposes
//{
// return Point{a.x + b.x, a.y + b.y};
//}
std::ostream& operator<<(std::ostream& os, Point const& pt) {
os << "[" << pt.x << "," << pt.y << "]";
return os;
};
struct Point3D {
double x;
double y;
double z;
};
std::ostream& operator<<(std::ostream& os, Point3D const& pt) {
os << "[" << pt.x << "," << pt.y << "," << pt.z << "]";
return os;
};
#include <chrono> // it's funny we don't need <chrono> for all the constexpr's above
using namespace std::chrono_literals;
template <class T>
std::ostream& operator<<(std::ostream& os, std::chrono::time_point<T> const& tp) {
os << tp.time_since_epoch().count();
return os;
};
int main()
{
Point pt1{1,2};
Point pt2{2,2};
std::cout << "(pt1 + pt2)/N " << pt1 << ", " << pt2 << " -> " << (pt1 + pt2)/N << std::endl;
std::cout << "(pt1 + pt2)/2 " << pt1 << ", " << pt2 << " -> " << (pt1 + pt2)/2 << std::endl;
auto c = pt1 + pt2;
c += Point{0,0};
c += 2*Point{1,1};
std::cout << std::endl;
std::cout << "c/0 " << pt1 << ", " << pt2 << " -> " << c/0 << std::endl;
std::cout << "10*pt1/N " << pt1 << " -> " << 10*pt1/N << std::endl;
std::cout << std::endl;
std::cout << "({1,2,3} + {3,2,1})/2 -> " << (Point3D{1,2,3} + Point3D{3,2,1})/2 << std::endl;
std::cout << std::endl;
auto tp1 = std::chrono::system_clock::now();
auto tp2 = tp1 + 2ms;
std::cout << "tp1 " << tp1 << std::endl;
std::cout << "tp2 " << tp2 << std::endl;
std::cout << "(tp1+tp2)/N " << (tp1+tp2)/N << std::endl;
std::cout << "using count() " << (tp1.time_since_epoch().count() + tp2.time_since_epoch().count())/2 << std::endl;
}
#include <iostream>
#include <chrono>
#include "boost/pfr/precise.hpp"
using namespace boost::pfr::ops; // operator<< for structures
enum SumOfWeights {
N
};
template <class Clock, class Duration>
std::ostream& operator<<(std::ostream& os, std::chrono::time_point<Clock, Duration> const& tp) {
os << tp.time_since_epoch().count();
return os;
};
template<class Point, class Weight = double>
class Combination {
public:
typedef Combination<Point, Weight> Self;
Combination(Self const&) = default;
Combination(Point const& t) {
sumOfWeights = 1;
accum = t;
}
Point operator/(SumOfWeights) const {
std::cerr << "{ operator/(SumOfWeights) } " << std::flush;
return affineCombination();
}
Point operator/(double w) const {
std::cerr << "{ operator/(" << w << ") } " << std::flush;
return affineCombination();
}
auto operator+=(Point const& other) {
return operator+=(Self(other));
}
auto operator+(Self const& other) const {
Self ret = *this;
return (ret += other);
}
auto operator*(double weight) const {
Self ret = *this;
return (ret *= weight);
}
auto operator+=(Self const& other) {
sumOfWeights += other.sumOfWeights;
add(other.accum);
return *this;
};
auto operator*=(Weight weight) {
sumOfWeights *= weight;
mul(accum, weight);
return *this;
};
private:
Combination() = delete;
Point affineCombination() const {
return affineCombination(accum);
}
template<class OtherPoint>
void add(OtherPoint const& other_point) {
static_assert( std::is_same<Point, OtherPoint>() );
typedef boost::pfr::tuple_element_t<0, Point> expected_field_t;
auto other_ptr = reinterpret_cast<expected_field_t const*>(&other_point);
boost::pfr::for_each_field(accum, [&other_ptr](auto& field) {
static_assert( std::is_same< decltype(field), expected_field_t& >() );
field += 0[other_ptr++];
});
};
template <class Clock, class Duration>
void add(std::chrono::time_point<Clock, Duration> const& other_point) {
accum += other_point.time_since_epoch();
};
template <class Clock, class Duration>
void mul(std::chrono::time_point<Clock, Duration>&, Weight factor) {
static_assert( std::is_same< typename Point::duration, Duration >() );
auto v = static_cast<typename Duration::rep>(accum.time_since_epoch().count() * factor);
accum = Point(Duration {v});
}
template <class OtherPoint>
void mul(OtherPoint&, Weight factor) {
static_assert(std::is_same<Point, OtherPoint>());
typedef boost::pfr::tuple_element_t<0, Point> expected_field_t;
boost::pfr::for_each_field(accum, [factor](auto& field) {
static_assert(std::is_same< decltype(field), expected_field_t& >() );
field *= factor;
});
};
template <class Clock, class Duration>
Point affineCombination(std::chrono::time_point<Clock, Duration> const& ) const {
std::cerr << "{ time_point " << accum << "/" << sumOfWeights << " } " << std::flush;
auto v = static_cast<typename Duration::rep>(accum.time_since_epoch().count() / sumOfWeights);
return Point(Duration {v});
}
template <class U>
Point affineCombination(U const& ) const {
static_assert(std::is_same<Point, U>());
typedef boost::pfr::tuple_element_t<0, Point> expected_field_t;
Point ret;
std::cerr << "{ tuple: " << accum << "/" << sumOfWeights << " } " << std::flush;
auto ret_ptr = reinterpret_cast<expected_field_t*>(&ret);
boost::pfr::for_each_field(accum, [&ret_ptr, this](auto field) {
static_assert(std::is_same< decltype(field), expected_field_t >() );
0[ret_ptr++] = static_cast<decltype(field)>( field / this->sumOfWeights );
});
return ret;
}
Weight sumOfWeights;
Point accum;
};
template <class Point>
Combination<Point> operator+(Point const& one, Point const& two) {
Combination<Point> ret(one);
return ret += two;
};
template <class Point>
Combination<Point> operator*(double weight, Point const& t) {
Combination<Point> ret(t);
return ret *= weight;
};
struct Point {
double x;
double y;
};
struct Point3D {
double x;
double y;
double z;
};
using namespace std::chrono_literals;
int main()
{
Point pt1{1,2}, pt2{2,2};
std::cout << "(pt1 + pt2)/N " << pt1 << ", " << pt2 << " -> " << (pt1 + pt2)/N << std::endl;
std::cout << "(pt1 + pt2)/2 " << pt1 << ", " << pt2 << " -> " << (pt1 + pt2)/2 << std::endl;
auto c = pt1 + pt2;
c += Point{0,0};
c += 2*Point{1,1};
std::cout << "c/0 " << " -> " << c/0 << std::endl;
std::cout << "10*pt1/N " << pt1 << " -> " << 10*pt1/N << std::endl;
std::cout << "({1,2,3} + {3,2,1})/2 -> " << (Point3D{1,2,3} + Point3D{3,2,1})/2 << std::endl;
auto tp1 = std::chrono::system_clock::now();
auto tp2 = tp1 + 2ms;
std::cout << "tp1 " << tp1 << std::endl;
std::cout << "tp2 " << tp2 << std::endl;
std::cout << "(tp1+tp2)/N " << (tp1+tp2)/N << std::endl;
std::cout << "(2*tp1+tp2)/N " << (2*tp1+tp2)/N << std::endl;
std::cout << "using count() " <<
(tp1.time_since_epoch().count() + tp2.time_since_epoch().count())/2 <<
", " <<
(2*tp1.time_since_epoch().count() + tp2.time_since_epoch().count())/3 <<
std::endl;
Combination<decltype(tp1), uint64_t> tpc(tp1);
tpc += tp2;
std::cout << "(tp1+tp2)/N " << tpc/N << std::endl;
tpc += tp1;
std::cout << "(2*tp1+tp2)/N " << tpc/N << std::endl;
}
@alexcohn
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment