Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset cf279270 in mainline


Ignore:
Timestamp:
2019-07-01T12:23:10Z (16 months ago)
Author:
Jaroslav Jindrak <dzejrou@…>
Branches:
master
Children:
396b234
Parents:
87efcb1
Message:

cpp: create promise_base and use it to implement all three versions of the promise template

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/__bits/thread/promise.hpp

    r87efcb1 rcf279270  
    4141     */
    4242
     43    namespace aux
     44    {
     45        template<class R>
     46        class promise_base
     47        {
     48            public:
     49                promise_base()
     50                    : state_{new aux::shared_state<R>{}}
     51                { /* DUMMY BODY */ }
     52
     53                template<class Allocator>
     54                promise_base(allocator_arg_t, const Allocator& a)
     55                    : promise_base{}
     56                {
     57                    // TODO: Use the allocator.
     58                }
     59
     60                promise_base(promise_base&& rhs) noexcept
     61                    : state_{}
     62                {
     63                    state_ = rhs.state_;
     64                    rhs.state_ = nullptr;
     65                }
     66
     67                promise_base(const promise_base&) = delete;
     68
     69                virtual ~promise_base()
     70                {
     71                    this->abandon_state_();
     72                }
     73
     74                promise_base& operator=(promise_base&& rhs) noexcept
     75                {
     76                    abandon_state_();
     77                    promise_base{std::move(rhs)}.swap(*this);
     78
     79                    return *this;
     80                }
     81
     82                promise_base& operator=(const promise_base&) = delete;
     83
     84                void swap(promise_base& other) noexcept
     85                {
     86                    std::swap(state_, other.state_);
     87                }
     88
     89                future<R> get_future()
     90                {
     91                    return future<R>{state_};
     92                }
     93
     94                void set_exception(exception_ptr ptr)
     95                {
     96                    assert(state_);
     97
     98                    state_->set_exception(ptr);
     99                }
     100
     101                void set_exception_at_thread_exit(exception_ptr)
     102                {
     103                    // TODO: No exception handling, no-op at this time.
     104                }
     105
     106            protected:
     107                void abandon_state_()
     108                {
     109                    /**
     110                     * Note: This is the 'abandon' move described in
     111                     *       30.6.4 (7).
     112                     * 1) If state is not ready:
     113                     *   a) Store exception of type future_error with
     114                     *      error condition broken_promise.
     115                     *   b) Mark state as ready.
     116                     * 2) Release the state.
     117                     */
     118                }
     119
     120                aux::shared_state<R>* state_;
     121        };
     122    }
     123
    43124    template<class R>
    44     class promise
     125    class promise: public aux::promise_base<R>
    45126    {
    46127        public:
    47128            promise()
    48                 : state_{new aux::shared_state<R>{}}
     129                : aux::promise_base<R>{}
    49130            { /* DUMMY BODY */ }
    50131
    51132            template<class Allocator>
    52133            promise(allocator_arg_t, const Allocator& a)
    53                 : promise{}
     134                : aux::promise_base<R>{}
    54135            {
    55136                // TODO: Use the allocator.
     
    57138
    58139            promise(promise&& rhs) noexcept
    59                 : state_{}
    60             {
    61                 state_ = rhs.state_;
    62                 rhs.state_ = nullptr;
    63             }
     140                : aux::promise_base<R>{move(rhs)}
     141            { /* DUMMY BODY */ }
    64142
    65143            promise(const promise&) = delete;
    66144
    67             ~promise()
    68             {
    69                 abandon_state_();
    70             }
    71 
    72             promise& operator=(promise&& rhs) noexcept
    73             {
    74                 abandon_state_();
    75                 promise{std::move(rhs)}.swap(*this);
    76             }
     145            ~promise() override = default;
     146
     147            promise& operator=(promise&& rhs) noexcept = default;
    77148
    78149            promise& operator=(const promise&) = delete;
    79150
    80             void swap(promise& other) noexcept
    81             {
    82                 std::swap(state_, other.state_);
    83             }
    84 
    85             future<R> get_future()
    86             {
    87                 return future<R>{state_};
    88             }
    89 
    90151            void set_value(const R& val)
    91152            {
    92                 if (!state_)
    93                     throw future_error{make_error_code(future_errc::no_state)};
    94                 if (state_->is_set())
    95                 {
    96                     throw future_error{
    97                         make_error_code(future_errc::promise_already_satisfied)
    98                     };
    99                 }
    100 
    101                 state_->set_value(val, true);
     153                if (!this->state_)
     154                    throw future_error{make_error_code(future_errc::no_state)};
     155                if (this->state_->is_set())
     156                {
     157                    throw future_error{
     158                        make_error_code(future_errc::promise_already_satisfied)
     159                    };
     160                }
     161
     162                this->state_->set_value(val, true);
    102163            }
    103164
    104165            void set_value(R&& val)
    105166            {
    106                 if (!state_)
    107                     throw future_error{make_error_code(future_errc::no_state)};
    108                 if (state_->is_set())
    109                 {
    110                     throw future_error{
    111                         make_error_code(future_errc::promise_already_satisfied)
    112                     };
    113                 }
    114 
    115                 state_->set_value(std::forward<R>(val), true);
    116             }
    117 
    118             void set_exception(exception_ptr ptr)
    119             {
    120                 assert(state_);
    121 
    122                 state_->set_exception(ptr);
     167                if (!this->state_)
     168                    throw future_error{make_error_code(future_errc::no_state)};
     169                if (this->state_->is_set())
     170                {
     171                    throw future_error{
     172                        make_error_code(future_errc::promise_already_satisfied)
     173                    };
     174                }
     175
     176                this->state_->set_value(std::forward<R>(val), true);
    123177            }
    124178
    125179            void set_value_at_thread_exit(const R& val)
    126180            {
    127                 if (!state_)
    128                     throw future_error{make_error_code(future_errc::no_state)};
    129                 if (state_->is_set())
    130                 {
    131                     throw future_error{
    132                         make_error_code(future_errc::promise_already_satisfied)
    133                     };
    134                 }
    135 
    136                 state_->set_value(val, false);
     181                if (!this->state_)
     182                    throw future_error{make_error_code(future_errc::no_state)};
     183                if (this->state_->is_set())
     184                {
     185                    throw future_error{
     186                        make_error_code(future_errc::promise_already_satisfied)
     187                    };
     188                }
     189
     190                this->state_->set_value(val, false);
    137191                // TODO: schedule it to be set as ready when thread exits
    138192            }
     
    140194            void set_value_at_thread_exit(R&& val)
    141195            {
    142                 if (!state_)
    143                     throw future_error{make_error_code(future_errc::no_state)};
    144                 if (state_->is_set())
    145                 {
    146                     throw future_error{
    147                         make_error_code(future_errc::promise_already_satisfied)
    148                     };
    149                 }
    150 
    151                 state_->set_value(std::forward<R>(val), false);
     196                if (!this->state_)
     197                    throw future_error{make_error_code(future_errc::no_state)};
     198                if (this->state_->is_set())
     199                {
     200                    throw future_error{
     201                        make_error_code(future_errc::promise_already_satisfied)
     202                    };
     203                }
     204
     205                this->state_->set_value(std::forward<R>(val), false);
    152206                // TODO: schedule it to be set as ready when thread exits
    153207            }
    154 
    155             void set_exception_at_thread_exit(exception_ptr)
    156             {
    157                 // TODO: No exception handling, no-op at this time.
    158             }
    159 
    160         private:
    161             void abandon_state_()
    162             {
    163                 /**
    164                  * Note: This is the 'abandon' move described in
    165                  *       30.6.4 (7).
    166                  * 1) If state is not ready:
    167                  *   a) Store exception of type future_error with
    168                  *      error condition broken_promise.
    169                  *   b) Mark state as ready.
    170                  * 2) Rekease the state.
    171                  */
    172             }
    173 
    174             aux::shared_state<R>* state_;
    175208    };
    176209
    177210    template<class R>
    178     class promise<R&>
    179     {
    180         // TODO: Copy & modify once promise is done.
     211    class promise<R&>: public aux::promise_base<R>
     212    { // TODO: I'm afraid we will need aux::shared_state<R&> specialization for this :/
     213        public:
     214            promise()
     215                : aux::promise_base<R&>{}
     216            { /* DUMMY BODY */ }
     217
     218            template<class Allocator>
     219            promise(allocator_arg_t, const Allocator& a)
     220                : aux::promise_base<R&>{}
     221            {
     222                // TODO: Use the allocator.
     223            }
     224
     225            promise(promise&& rhs) noexcept
     226                : aux::promise_base<R&>{move(rhs)}
     227            { /* DUMMY BODY */ }
     228
     229            promise(const promise&) = delete;
     230
     231            ~promise() override = default;
     232
     233            promise& operator=(promise&& rhs) noexcept = default;
     234
     235            promise& operator=(const promise&) = delete;
    181236    };
    182237
    183238    template<>
    184     class promise<void>
    185     {
    186         // TODO: Copy & modify once promise is done.
     239    class promise<void>: public aux::promise_base<void>
     240    {
     241        public:
     242            promise()
     243                : aux::promise_base<void>{}
     244            { /* DUMMY BODY */ }
     245
     246            template<class Allocator>
     247            promise(allocator_arg_t, const Allocator& a)
     248                : aux::promise_base<void>{}
     249            {
     250                // TODO: Use the allocator.
     251            }
     252
     253            promise(promise&& rhs) noexcept
     254                : aux::promise_base<void>{move(rhs)}
     255            { /* DUMMY BODY */ }
     256
     257            promise(const promise&) = delete;
     258
     259            ~promise() override = default;
     260
     261            promise& operator=(promise&& rhs) noexcept = default;
     262
     263            promise& operator=(const promise&) = delete;
     264
     265            void set_value()
     266            {
     267                if (!this->state_)
     268                    throw future_error{make_error_code(future_errc::no_state)};
     269                if (this->state_->is_set())
     270                {
     271                    throw future_error{
     272                        make_error_code(future_errc::promise_already_satisfied)
     273                    };
     274                }
     275
     276                this->state_->set_value();
     277            }
    187278    };
    188279
Note: See TracChangeset for help on using the changeset viewer.