Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017

5,007 views

Published on

Полная версия доклада. Описание: http://2017.cppconf.ru/talks/mikhail-matrosov

Published in: Software
  • Be the first to comment

Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017

  1. 1. Повседневный С++: алгоритмы и итераторы Михаил Матросов mikhail.matrosov@gmail.com mmatrosov@aligntech.com 1
  2. 2. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 2
  3. 3. goo.gl/TL15Rg "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 33 С++17 С++11/14 С++98 С High level Expert level Modern C++ Almost the same :(
  4. 4. “Within C++ is a smaller, simpler, safer language struggling to get out” Bjarne Stroustrup "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 4
  5. 5. High level:  Парадигма RAII и исключения (exceptions)  Семантика перемещения  λ-функции  Классы и конструкторы  Простые шаблоны  STL  Утилиты и алгоритмы boost "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 5 Expert level:  Операторы new/delete, владеющие указатели  Пользовательские операции копирования и перемещения  Пользовательские деструкторы  Закрытое, защищённое, ромбовидное, виртуальное наследование  Шаблонная магия  Все функции языка Си, препроцессор  «Голые» циклы Классический слайд с телом и заголовком
  6. 6. 6 Which boost features overlap with C++11?
  7. 7. const std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; result.clear(); if (points.size() == 0) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; } int q = 0; found = false; for (int i = 1; i < points.size() && ~found; ++i) 7
  8. 8. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 8 const std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; result.clear(); if (points.size() == 0) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; } int q = 0; found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x >= 0 && points[i].x < 0) { q = i; found = true; } if (p == q) { if ((*points.begin()).x >= 0) return points; else return result; } int i = p; while (i != q) { if (points[i].x < 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } result.push_back(points[i]); if (++i >= points.size()) i = 0; } i = q; while (i != p) { if (points[i].x >= 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } if (++i >= points.size()) i = 0; } return std::move(result); } std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); if (!is_partitioned(points, isRight)) throw std::runtime_error("Unexpected order"); points.erase(partition_point(points, isRight), points.end()); return points; }
  9. 9. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 9 const std::vector<Point> extract(const std::vector<Point>& points) {
  10. 10. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 10 std::vector<Point> extract(const std::vector<Point>& points) {
  11. 11. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 11 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; result.clear();
  12. 12. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 12 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result;
  13. 13. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 13 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.size() == 0) return result;
  14. 14. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 14 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result;
  15. 15. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 15 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; }
  16. 16. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 16 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && !found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; }
  17. 17. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 17 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result; int p = 0; bool found = false; for (int i = 1; i < points.size(); ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; break; }
  18. 18. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 18 int p = 0; for (int i = 1; i < points.size(); ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; break; } int q = 0; for (int i = 1; i < points.size(); ++i) if (points[i - 1].x >= 0 && points[i].x < 0) { q = i; break; }
  19. 19. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 19 auto isRight = [](const Point& pt) { return pt.x >= 0; }; int p = 0; for (int i = 1; i < points.size(); ++i) if (!isRight(points[i - 1]) && isRight(points[i])) { p = i; break; } int q = 0; for (int i = 1; i < points.size(); ++i) if (isRight(points[i - 1]) && !isRight(points[i])) { q = i; break; }
  20. 20. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 20 auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto find = [&](bool flag) { for (int i = 1; i < points.size(); ++i) if (isRight(points[i - 1]) == flag && isRight(points[i]) != flag) return i; return 0; }; int p = find(false); int q = find(true);
  21. 21. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 21 auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto findBoundary = [&](bool rightToLeft) { for (int i = 1; i < points.size(); ++i) if (isRight(points[i - 1]) == rightToLeft && isRight(points[i]) != rightToLeft) return i; return 0; }; int p = findBoundary(false); int q = findBoundary(true);
  22. 22. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 22 int p = findBoundary(false); int q = findBoundary(true); if (p == q) { if (isRight(*points.begin())) return points; else return result; }
  23. 23. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 23 int p = findBoundary(false); int q = findBoundary(true); if (p == q) { if (isRight(points[0])) return points; else return result; }
  24. 24. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 24 int p = findBoundary(false); int q = findBoundary(true); if (p == q) return isRight(points[0]) ? points : result;
  25. 25. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 25 if (p == q) return isRight(points[0]) ? points : result; int i = p; while (i != q) { if (!isRight(points[i])) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } result.push_back(points[i]); if (++i >= points.size()) i = 0; }
  26. 26. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 26 if (p == q) return isRight(points[0]) ? points : result; int i = p; while (i != q) { if (!isRight(points[i])) return { Point(NAN, NAN) }; result.push_back(points[i]); if (++i >= points.size()) i = 0; } std::numeric_limits::quiet_NaN() vs. std::nan() vs. NAN
  27. 27. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 27 int i = p; while (i != q) { if (!isRight(points[i])) return { Point(NAN, NAN) }; result.push_back(points[i]); if (++i >= points.size()) i = 0; } i = q; while (i != p) { if (isRight(points[i])) return { Point(NAN, NAN) }; if (++i >= points.size()) i = 0; }
  28. 28. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 28 int i = p; while (i != q) { if (!isRight(points[i])) return { Point(NAN, NAN) }; result.push_back(points[i]); if (++i >= points.size()) i = 0; } i = q; while (i != p) { if (isRight(points[i])) return { Point(NAN, NAN) }; if (++i >= points.size()) i = 0; }
  29. 29. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 29 auto appendResult = [&](int from, int to, bool shouldBeRight) { int i = from; while (i != to) { if (isRight(points[i]) != shouldBeRight) { result = { Point(NAN, NAN) }; return false; } if (shouldBeRight) result.push_back(points[i]); if (++i >= points.size()) i = 0; } return true; }; bool success = appendResult(p, q, true) && appendResult(q, p, false);
  30. 30. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 30 auto appendResult = [&](int from, int to, bool shouldBeRight) { int i = from; while (i != to) { if (isRight(points[i]) != shouldBeRight) throw std::runtime_error("Unexpected order"); if (shouldBeRight) result.push_back(points[i]); if (++i >= points.size()) i = 0; } }; appendResult(p, q, true); appendResult(q, p, false);
  31. 31. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 31 appendResult(p, q, true); appendResult(q, p, false); return std::move(result); }
  32. 32. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 32 appendResult(p, q, true); appendResult(q, p, false); return result; }
  33. 33. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 33 std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto findBoundary = [&](bool rightToLeft) { for (int i = 1; i < points.size(); ++i) if (isRight(points[i - 1]) == rightToLeft && isRight(points[i]) != rightToLeft) return i; return 0; }; int p = findBoundary(false); int q = findBoundary(true); if (p == q) return isRight(points[0]) ? points : result; auto appendResult = [&](int from, int to, bool shouldBeRight) { int i = from; while (i != to) { if (isRight(points[i]) != shouldBeRight) throw std::runtime_error("Unexpected order"); if (shouldBeRight) result.push_back(points[i]); if (++i >= points.size()) i = 0; } }; appendResult(p, q, true); appendResult(q, p, false); return result; } const std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; result.clear(); if (points.size() == 0) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; } int q = 0; found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x >= 0 && points[i].x < 0) { q = i; found = true; } if (p == q) { if ((*points.begin()).x >= 0) return points; else return result; } int i = p; while (i != q) { if (points[i].x < 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } result.push_back(points[i]); if (++i >= points.size()) i = 0; } i = q; while (i != p) { if (points[i].x >= 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } if (++i >= points.size()) i = 0; } return std::move(result); } int p = findBoundary(false); int q = findBoundary(true); appendResult(p, q, true); appendResult(q, p, false);
  34. 34. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 34 0 1 2 3 4 5 6 1 2 3 4 0 1 2 3 4 5 6 qp p q 0 1 2 3 4 5 6 4 5 6 0 1 pq
  35. 35. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 35 0 1 2 3 4 5 6 1. Найти первый элемент 2. Сдвинуть его в началоp
  36. 36. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 36 6 0 1 2 3 4 5 1. Найти первый элемент 2. Сдвинуть его в начало
  37. 37. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 37 5 6 0 1 2 3 4 1. Найти первый элемент 2. Сдвинуть его в начало
  38. 38. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 38 5 6 0 1 2 34 1. Найти первый элемент 2. Сдвинуть его в начало 3. Проверить структуру 4. Выкинуть хвост 5. Вернуть что осталось
  39. 39. std::vector<Point> extractRight(std::vector<Point> points) { "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 39
  40. 40. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 40
  41. 41. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 41
  42. 42. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 42
  43. 43. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); if (!is_partitioned(points, isRight)) throw std::runtime_error("Unexpected order"); "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 43
  44. 44. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); if (!is_partitioned(points, isRight)) throw std::runtime_error("Unexpected order"); points.erase(partition_point(points, isRight), points.end()); "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 44
  45. 45. std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); if (!is_partitioned(points, isRight)) throw std::runtime_error("Unexpected order"); points.erase(partition_point(points, isRight), points.end()); return points; } "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 45
  46. 46. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 46 const std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; result.clear(); if (points.size() == 0) return result; int p = 0; bool found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x < 0 && points[i].x >= 0) { p = i; found = true; } int q = 0; found = false; for (int i = 1; i < points.size() && ~found; ++i) if (points[i - 1].x >= 0 && points[i].x < 0) { q = i; found = true; } if (p == q) { if ((*points.begin()).x >= 0) return points; else return result; } int i = p; while (i != q) { if (points[i].x < 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } result.push_back(points[i]); if (++i >= points.size()) i = 0; } i = q; while (i != p) { if (points[i].x >= 0) { result.clear(); Point nan; nan.x = sqrt(-1); nan.y = sqrt(-1); result.push_back(nan); return result; } if (++i >= points.size()) i = 0; } return std::move(result); } std::vector<Point> extractRight(std::vector<Point> points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); if (middle != points.end()) rotate(points, std::next(middle)); if (!is_partitioned(points, isRight)) throw std::runtime_error("Unexpected order"); points.erase(partition_point(points, isRight), points.end()); return points; } std::vector<Point> extract(const std::vector<Point>& points) { std::vector<Point> result; if (points.empty()) return result; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto findBoundary = [&](bool rightToLeft) { for (int i = 1; i < points.size(); ++i) if (isRight(points[i - 1]) == rightToLeft && isRight(points[i]) != rightToLeft) return i; return 0; }; int p = findBoundary(false); int q = findBoundary(true); if (p == q) return isRight(points[0]) ? points : result; auto appendResult = [&](int from, int to, bool shouldBeRight) { int i = from; while (i != to) { if (isRight(points[i]) != shouldBeRight) throw std::runtime_error("Unexpected order"); if (shouldBeRight) result.push_back(points[i]); if (++i >= points.size()) i = 0; } }; appendResult(p, q, true); appendResult(q, p, false); return result; }
  47. 47. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 47 0 1 2 3 middlefirst last 4 5 6
  48. 48. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 48 Sean Parent: C++ Seasoning (no raw loops)
  49. 49. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 49
  50. 50. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 50
  51. 51. 0 1 2 3 4 5 6 0 1 2 3 4 "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 51 0 1 2 3 4 5 6 Ответ! Результат rotate()!
  52. 52. 52 template<class It> class WrappingIterator : public boost::iterator_adaptor<WrappingIterator<It>, It> { using Base = boost::iterator_adaptor<WrappingIterator<It>, It>; public: WrappingIterator() = default; WrappingIterator(It it, It begin, It end) : Base(it), m_end(end), m_size(end - begin) {} private: friend class boost::iterator_core_access; typename Base::reference dereference() const { auto it = this->base_reference(); return *(it < m_end ? it : it - m_size); } It m_end; size_t m_size; };
  53. 53. 53 template<class It> class WrappingIterator : public boost::iterator_facade<WrappingIterator<It>, typename It::value_type, boost::random_access_traversal_tag, typename It::reference> { public: WrappingIterator() = default; WrappingIterator(It it, It begin, It end) : m_begin(begin), m_size(end - begin), m_offset(it - begin) {} template <class OtherIt> WrappingIterator(const WrappingIterator<OtherIt>& other) : m_begin(other.m_begin), m_size(other.m_size), m_offset(other.m_offset) {} private: friend class boost::iterator_core_access; template<class> friend class WrappingIterator; using Base = boost::iterator_facade<WrappingIterator<It>, typename It::value_type, boost::random_access_traversal_tag, typename It::reference>; // Core interface functions (on the next slide) It m_begin; size_t m_size; size_t m_offset; };
  54. 54. 54 typename Base::reference dereference() const { return *(m_begin + (m_offset < m_size ? m_offset : m_offset - m_size)); } template <class OtherIt> bool equal(const WrappingIterator<OtherIt>& other) const { assert(other.m_begin == m_begin && other.m_size == m_size); return other.m_offset == m_offset; } void advance(typename Base::difference_type n) { m_offset += n; } void increment() { ++m_offset; } void decrement() { --m_offset; } template <class OtherIt> typename Base::difference_type distance_to(const WrappingIterator<OtherIt>& other) const { assert(other.m_begin == m_begin && other.m_size == m_size); return other.m_offset - m_offset; }
  55. 55. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 55 template<class It> auto makeWrappingIterator(It it, It begin, It end) { return WrappingIterator<It>(it, begin, end); }
  56. 56. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 56 auto extractRight(const std::vector<Point>& points) {
  57. 57. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 57 auto extractRight(const std::vector<Point>& points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); });
  58. 58. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 58 auto extractRight(const std::vector<Point>& points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); middle = middle != points.end() ? std::next(middle) : points.begin(); auto begin = makeWrappingIterator(middle, points.begin(), points.end()); auto rotated = boost::make_iterator_range(begin, begin + points.size());
  59. 59. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 59 auto extractRight(const std::vector<Point>& points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); middle = middle != points.end() ? std::next(middle) : points.begin(); auto begin = makeWrappingIterator(middle, points.begin(), points.end()); auto rotated = boost::make_iterator_range(begin, begin + points.size()); if (!is_partitioned(rotated, isRight)) throw std::runtime_error("Unexpected order");
  60. 60. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 60 auto extractRight(const std::vector<Point>& points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); middle = middle != points.end() ? std::next(middle) : points.begin(); auto begin = makeWrappingIterator(middle, points.begin(), points.end()); auto rotated = boost::make_iterator_range(begin, begin + points.size()); if (!is_partitioned(rotated, isRight)) throw std::runtime_error("Unexpected order"); auto end = partition_point(rotated, isRight);
  61. 61. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 61 auto extractRight(const std::vector<Point>& points) { using namespace boost::range; using namespace boost::algorithm; auto isRight = [](const Point& pt) { return pt.x >= 0; }; auto middle = adjacent_find(points, [&](auto&& pt1, auto&& pt2) { return !isRight(pt1) && isRight(pt2); }); middle = middle != points.end() ? std::next(middle) : points.begin(); auto begin = makeWrappingIterator(middle, points.begin(), points.end()); auto rotated = boost::make_iterator_range(begin, begin + points.size()); if (!is_partitioned(rotated, isRight)) throw std::runtime_error("Unexpected order"); auto end = partition_point(rotated, isRight); return boost::make_iterator_range(begin, end); }
  62. 62. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 62 0 1 2 3 4 5 6 Раз……два!
  63. 63. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 63 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) {
  64. 64. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 64 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) { using namespace boost::range; using namespace boost::algorithm; auto middle = adjacent_find(first, last, [&](auto&& a, auto&& b) { return !p(a) && p(b); }); middle = middle != last ? std::next(middle) : first;
  65. 65. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 65 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) { using namespace boost::range; using namespace boost::algorithm; auto middle = adjacent_find(first, last, [&](auto&& a, auto&& b) { return !p(a) && p(b); }); middle = middle != last ? std::next(middle) : first; auto rotated = boost::join(boost::make_iterator_range(middle, last), boost::make_iterator_range(first, middle));
  66. 66. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 66 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) { using namespace boost::range; using namespace boost::algorithm; auto middle = adjacent_find(first, last, [&](auto&& a, auto&& b) { return !p(a) && p(b); }); middle = middle != last ? std::next(middle) : first; auto rotated = boost::join(boost::make_iterator_range(middle, last), boost::make_iterator_range(first, middle)); if (!is_partitioned(rotated, p)) throw std::runtime_error("Unexpected order");
  67. 67. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 67 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) { using namespace boost::range; using namespace boost::algorithm; auto middle = adjacent_find(first, last, [&](auto&& a, auto&& b) { return !p(a) && p(b); }); middle = middle != last ? std::next(middle) : first; auto rotated = boost::join(boost::make_iterator_range(middle, last), boost::make_iterator_range(first, middle)); if (!is_partitioned(rotated, p)) throw std::runtime_error("Unexpected order"); auto end = partition_point(rotated, p);
  68. 68. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 68 template<class It, class Predicate> auto extractIf(It first, It last, Predicate p) { using namespace boost::range; using namespace boost::algorithm; auto middle = adjacent_find(first, last, [&](auto&& a, auto&& b) { return !p(a) && p(b); }); middle = middle != last ? std::next(middle) : first; auto rotated = boost::join(boost::make_iterator_range(middle, last), boost::make_iterator_range(first, middle)); if (!is_partitioned(rotated, p)) throw std::runtime_error("Unexpected order"); auto end = partition_point(rotated, p); return boost::make_iterator_range(rotated.begin(), end); }
  69. 69.  Ответь на вопрос  Получи мячик  …  PROFIT! "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 69
  70. 70. Performance? Range Traverse time std::vector 1.0 Joined range of two iterator ranges "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 70 100M elements double sum = 0; for (const Point& v : range) sum += v.x;
  71. 71. Performance? Range Traverse time std::vector 1.0 Joined range of two iterator ranges 1.18 "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 71 100M elements double sum = 0; for (const Point& v : range) sum += v.x;
  72. 72. "Повседневный С++: алгоритмы и итераторы", Михаил Матросов, Конференция C++ Russia 2017 72  Мыслите в терминах алгоритмов  Код должен ясно выражать намерение  Знайте свои инструменты и используйте их к месту // lambda functions (including generic) // ternary operator // exceptions // transient parameters std::vector<T>::empty() adjacent_find() rotate() is_partitioned() partition_point() std::next(); // custom make-function // template parameters for iterators // template parameters for predicates // function return type deduction boost::range boost::algorithm boost::iterator_adaptor<It> boost::make_iterator_range() boost::join() Спасибо за внимание!

×