Advertisement
alaestor

[FGL Utility] FlaggedPointer.h

Feb 5th, 2018
269
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.29 KB | None | 0 0
  1. // Alaestor - FGL
  2. // Public Discord Invite: http://public.FutureGadgetLab.net
  3.  
  4. #ifndef FLAGGEDPOINTER_H_INCLUDED
  5. #define FLAGGEDPOINTER_H_INCLUDED
  6.  
  7. #include <cstddef>
  8. #include <memory>
  9.  
  10. /*
  11.     Flagged pointers use the least significant bit of a pointer
  12.     to encode boolean state. It requires the type to be larger
  13.     than char, and the address must be even (low bit zero).
  14.     Use alignas(2) to solve the "odd address" issue
  15.     where the low bit could be 1 in some environments.
  16.  
  17.     This header proves two classes. flagged_unique_ptr provides
  18.     RAII, custom deleter, and smartpointer support, where as
  19.     flagged_ptr is a raw pointer and provides itterative support.
  20. */
  21.  
  22. namespace FGL {
  23.  
  24. static constexpr bool OddPointerSafetyChecks = false;
  25.  
  26. template <class T, class Deleter = std::default_delete< T >>
  27. class flagged_unique_ptr // lacks support for std::make_unique
  28. {
  29.     public:
  30.     using value_type = T;
  31.     using this_type = flagged_unique_ptr<value_type, Deleter>;
  32.     using difference_type = std::ptrdiff_t;
  33.     using pointer = value_type*;
  34.     using reference = value_type&;
  35.  
  36.     private:
  37.     std::unique_ptr<value_type, Deleter> m_uptr;
  38.  
  39.     public:
  40.     bool flag() const noexcept
  41.     { return (reinterpret_cast< difference_type >(m_uptr.get()) & 1); }
  42.  
  43.     bool setflag(const bool& state)
  44.     {
  45.         if (state)
  46.         {
  47.             const auto& addr = m_uptr.release();
  48.             m_uptr.reset(reinterpret_cast< pointer >(
  49.                 reinterpret_cast< difference_type >(addr) | 1));
  50.         }
  51.         else
  52.         {
  53.             const auto& addr = m_uptr.release();
  54.             m_uptr.reset(reinterpret_cast< pointer >(
  55.                 reinterpret_cast< difference_type >(addr) & ~1));
  56.         }
  57.         return state;
  58.     }
  59.  
  60.     void toggleflag() noexcept
  61.     {
  62.         const auto& addr = m_uptr.release();
  63.         m_uptr.reset(reinterpret_cast< pointer >(
  64.             reinterpret_cast< difference_type >(addr) ^ 1));
  65.     }
  66.  
  67.     pointer get() const noexcept
  68.     {
  69.         return reinterpret_cast< pointer >( // corrects address
  70.             reinterpret_cast< difference_type >(m_uptr.get()) & ~1);
  71.     }
  72.  
  73.     pointer release() noexcept // preserves flag state
  74.     {
  75.         const auto& oldFlagState = flag();
  76.         setflag(false); // corrects address
  77.         const auto& p = m_uptr.release();
  78.         setflag(oldFlagState);
  79.         return p;
  80.     }
  81.  
  82.     void reset(const pointer& p = nullptr) noexcept // sets flag to false
  83.     {
  84.         setflag(false);
  85.         m_uptr.reset(p);
  86.     }
  87.  
  88.     void swap(decltype(m_uptr)& up) noexcept // sets flag to false
  89.     {
  90.         setflag(false); // corrects address
  91.         m_uptr.swap(up);
  92.     }
  93.  
  94.     void swap(this_type& fup) noexcept // preserves flag state
  95.     { m_uptr.swap(fup.m_uptr); }
  96.  
  97.     Deleter& get_deleter() noexcept
  98.     { return m_uptr.get_deleter(); }
  99.  
  100.     const Deleter& get_deleter() const noexcept
  101.     { return m_uptr.get_deleter(); }
  102.  
  103.  
  104.     // container comparative operators
  105.     bool operator==(const decltype(m_uptr)& up) const noexcept
  106.     { return m_uptr == up; }
  107.  
  108.     bool operator!=(const decltype(m_uptr)& up) const noexcept
  109.     { return !operator==(up); }
  110.  
  111.     bool operator==(const this_type& fup) const noexcept
  112.     { return m_uptr == fup.m_uptr; }
  113.  
  114.     bool operator!=(const this_type& fup) const noexcept
  115.     { return !operator==(fup); }
  116.  
  117.  
  118.     // assignment
  119.     this_type& operator=(this_type& fup) noexcept
  120.     {
  121.         reset(fup.m_ptr.release());
  122.         return *this;
  123.     }
  124.  
  125.     bool operator=(const bool& b) noexcept
  126.     { return setflag(b); }
  127.  
  128.  
  129.     // pointer arithmatic operators
  130.     pointer operator+(const difference_type& i) const noexcept
  131.     { return get() + i; }
  132.  
  133.     pointer operator-(const difference_type& i) const noexcept
  134.     { return get() - i; }
  135.  
  136.     difference_type operator-(const pointer& p) const noexcept // type?
  137.     { return get() - p; }
  138.  
  139.  
  140.     // pointer dereference operators
  141.     pointer operator->() const noexcept
  142.     { return (get()); }
  143.  
  144.     reference operator*()
  145.     { return *(get()); }
  146.  
  147.     reference operator[](const difference_type& i)
  148.     { return get()[i]; }
  149.  
  150.     const reference operator*() const
  151.     { return *(get()); }
  152.  
  153.     const reference operator[](const difference_type& i) const
  154.     { return get()[i]; }
  155.  
  156.  
  157.     // pointer comparative operators
  158.     bool operator<(const pointer& p) const noexcept
  159.     { return get() < p; }
  160.  
  161.     bool operator>(const pointer& p) const noexcept
  162.     { return get() > p; }
  163.  
  164.     bool operator<=(const pointer& p) const noexcept
  165.     { return get() <= p; }
  166.  
  167.     bool operator>=(const pointer& p) const noexcept
  168.     { return get() >= p; }
  169.  
  170.     bool operator==(const pointer& p) const noexcept
  171.     { return get() == p; }
  172.  
  173.     bool operator!=(const pointer& p) const noexcept
  174.     { return !operator==(p); }
  175.  
  176.  
  177.     // boolean operators (affect flag)
  178.     bool operator==(const bool& b) const noexcept
  179.     { return flag() == b; }
  180.  
  181.     bool operator!=(const bool& b) const noexcept
  182.     { return !operator==(b); }
  183.  
  184.  
  185.     // conversion operators
  186.     explicit operator pointer() const noexcept
  187.     { return get(); }
  188.  
  189.     explicit operator bool() const noexcept // unique_ptr behavior
  190.     { return get() != nullptr; }
  191.  
  192.  
  193.     // stop annoying implicit conversions
  194.     void operator=(const int&) = delete; // stop implicit int->bool convert.
  195.     void operator=(const difference_type&) = delete; // stop (this = &) convert
  196.     void operator=(const pointer&) = delete; // stop (this = &) convert
  197.  
  198.  
  199.     flagged_unique_ptr(pointer ptr = nullptr)
  200.     : m_uptr(ptr)
  201.     {
  202.         static_assert(alignof(value_type) >= 2, //old: sizeof(T) > sizeof(char)
  203.             "FGL::FlaggedPointer: Type size must be aligned by >= 2");
  204.  
  205.         if constexpr (OddPointerSafetyChecks)
  206.             if (reinterpret_cast< difference_type >(ptr) & 1)
  207.                 throw "constructed with odd address! Weird enviroment!";
  208.  
  209.     }
  210.  
  211.     ~flagged_unique_ptr() // corrects address so unique_ptr can do it's thing
  212.     { setflag(false); }
  213. };
  214.  
  215. template <typename T>
  216. class flagged_ptr : std::random_access_iterator_tag
  217. {
  218.     public:
  219.     using value_type = T;
  220.     using this_type = flagged_ptr<value_type>;
  221.     using difference_type = std::ptrdiff_t;
  222.     using pointer = value_type*;
  223.     using reference = value_type&;
  224.     using iterator_category = std::random_access_iterator_tag;
  225.  
  226.     private:
  227.     pointer m_address;
  228.  
  229.     protected:
  230.     pointer assign(const pointer& p) noexcept
  231.     {
  232.         const auto& oldFlagState = flag();
  233.         m_address = p;
  234.         setflag(oldFlagState);
  235.         return p;
  236.     }
  237.  
  238.     public:
  239.     bool flag() const noexcept
  240.     { return (reinterpret_cast< difference_type >(m_address) & 1); }
  241.  
  242.     bool setflag(const bool& state) noexcept
  243.     {
  244.         if (state)
  245.         {
  246.             m_address = reinterpret_cast< pointer >(
  247.                 reinterpret_cast< difference_type >(m_address) | 1);
  248.         }
  249.         else
  250.         {
  251.             m_address = reinterpret_cast< pointer >(
  252.                 reinterpret_cast< difference_type >(m_address) & ~1);
  253.         }
  254.         return state;
  255.     }
  256.  
  257.     void toggleflag() noexcept
  258.     {
  259.         m_address = reinterpret_cast< pointer >(
  260.             reinterpret_cast< difference_type >(m_address) ^ 1);
  261.     }
  262.  
  263.     pointer get() const noexcept
  264.     {
  265.         return reinterpret_cast< pointer >(
  266.             reinterpret_cast< difference_type >(m_address) & ~1);
  267.     }
  268.  
  269.  
  270.     // container operators
  271.     bool operator==(const this_type& fp) const noexcept
  272.     { return m_address == fp.m_address; }
  273.  
  274.     bool operator!=(const this_type& fp) const noexcept
  275.     { return !operator==(fp.m_address); }
  276.  
  277.  
  278.     // assignment
  279.     pointer operator=(const this_type& fp) noexcept
  280.     { return m_address = fp.m_address; }
  281.  
  282.     pointer operator=(const pointer& p) noexcept
  283.     { return assign(p); }
  284.  
  285.     bool operator=(const bool& b) noexcept
  286.     { return setflag(b); }
  287.  
  288.  
  289.     // pointer arithmatic operators
  290.     pointer operator+(const difference_type& i) const noexcept
  291.     { return get() + i; }
  292.  
  293.     pointer operator-(const difference_type& i) const noexcept
  294.     { return get() - i; }
  295.  
  296.     pointer operator*(const difference_type& i) const noexcept
  297.     { return get() * i; }
  298.  
  299.     pointer operator/(const difference_type& i) const noexcept
  300.     { return get() / i; }
  301.  
  302.     pointer operator%(const difference_type& i) const noexcept
  303.     { return get() % i; }
  304.  
  305.     pointer operator+=(const difference_type& i) noexcept
  306.     { return assign(operator+(i)); }
  307.  
  308.     pointer operator-=(const difference_type& i) noexcept
  309.     { return assign(operator-(i)); }
  310.  
  311.     pointer operator*=(const difference_type& i) noexcept
  312.     { return assign(operator*(i)); }
  313.  
  314.     pointer operator/=(const difference_type& i) noexcept
  315.     { return assign(operator/(i)); }
  316.  
  317.     pointer operator%=(const difference_type& i) noexcept
  318.     { return assign(operator%(i)); }
  319.  
  320.     pointer operator++() noexcept
  321.     { return operator+=(1); }
  322.  
  323.     pointer operator--() noexcept
  324.     { return operator-=(1); }
  325.  
  326.     pointer operator++(int) noexcept
  327.     {
  328.         const auto& p = get();
  329.         operator++();
  330.         return p;
  331.     }
  332.  
  333.     pointer operator--(int) noexcept
  334.     {
  335.         const auto& p = get();
  336.         operator--();
  337.         return p;
  338.     }
  339.  
  340.     difference_type operator-(const pointer& p) const noexcept
  341.     { return get() - p; }
  342.  
  343.  
  344.     // pointer dereference operators
  345.     pointer operator->() const noexcept
  346.     { return get(); }
  347.  
  348.     reference operator*()
  349.     { return *(get()); }
  350.  
  351.     reference operator[](const difference_type& i)
  352.     { return get()[i]; }
  353.  
  354.     const reference operator*() const
  355.     { return *(get()); }
  356.  
  357.     const reference operator[](const difference_type& i) const
  358.     { return get()[i]; }
  359.  
  360.  
  361.     // pointer comparitive operators
  362.     bool operator<(const pointer& p) const noexcept
  363.     { return get() < p; }
  364.  
  365.     bool operator>(const pointer& p) const noexcept
  366.     { return get() > p; }
  367.  
  368.     bool operator<=(const pointer& p) const noexcept
  369.     { return get() <= p; }
  370.  
  371.     bool operator>=(const pointer& p) const noexcept
  372.     { return get() >= p; }
  373.  
  374.     bool operator==(const pointer& p) const noexcept
  375.     { return get() == p; }
  376.  
  377.     bool operator!=(const pointer& p) const noexcept
  378.     { return !operator==(p); }
  379.  
  380.  
  381.     // boolean operators (affect flag)
  382.     bool operator=(const bool& b) const noexcept
  383.     { return setflag(b); }
  384.  
  385.     bool operator==(const bool& b) const noexcept
  386.     { return flag() == b; }
  387.  
  388.     bool operator!=(const bool& b) const noexcept
  389.     { return !operator==(b); }
  390.  
  391.  
  392.     // conversion operators
  393.     explicit operator pointer() const noexcept
  394.     { return get(); }
  395.  
  396.  
  397.     // stop annoying implicit conversions
  398.     void operator=(const int&) = delete; // stop implicit int->bool convert.
  399.     void operator=(const difference_type&) = delete; // stop (this = &) convert
  400.  
  401.  
  402.     flagged_ptr(T* ptr = nullptr)
  403.     : m_address(ptr)
  404.     {
  405.         static_assert(alignof(value_type) >= 2, //old: sizeof(T) > sizeof(char)
  406.             "FGL::FlaggedPointer: Type size must be aligned by >= 2");
  407.  
  408.         if constexpr (OddPointerSafetyChecks)
  409.             if (reinterpret_cast< difference_type >(ptr) & 1)
  410.                 throw "constructed with odd address! Weird enviroment!";
  411.     }
  412.  
  413.     ~flagged_ptr() = default;
  414. };
  415.  
  416. } // namespace FGL
  417.  
  418. #endif // FLAGGEDPOINTER_H_INCLUDED
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement