Last active
August 24, 2019 09:47
-
-
Save alexcohn/e38642f772d7bbfa62baaca0fd1ad0da to your computer and use it in GitHub Desktop.
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
#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; | |
} |
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
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks to Anton Polukhin (Yandex)
https://github.com/apolukhin/magic_get
https://www.youtube.com/watch?v=abdeAew3gmQ