#pragma once /* * Copyright 2018-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include namespace pushmi { // traits & tags // cardinality affects both sender and receiver struct cardinality_category {}; // Trait template struct has_cardinality : category_query {}; template PUSHMI_INLINE_VAR constexpr bool has_cardinality_v = has_cardinality::value; PUSHMI_CONCEPT_DEF( template(class PS) concept Cardinality, has_cardinality_v); // flow affects both sender and receiver struct flow_category {}; // sender and receiver are mutually exclusive struct receiver_category {}; struct sender_category {}; // for senders that are executors struct executor_category {}; // time and constrained are mutually exclusive refinements of sender (time is a // special case of constrained and may be folded in later) // blocking affects senders struct blocking_category {}; // sequence affects senders struct sequence_category {}; // Single trait and tag template struct is_single; // Tag template <> struct is_single<> { using property_category = cardinality_category; }; // Trait template struct is_single : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_single_v = is_single::value; PUSHMI_CONCEPT_DEF(template(class PS) concept Single, is_single_v); // Many trait and tag template struct is_many; // Tag template <> struct is_many<> { using property_category = cardinality_category; }; // many::value() does not terminate, so it is not a refinement of single // Trait template struct is_many : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_many_v = is_many::value; PUSHMI_CONCEPT_DEF(template(class PS) concept Many, is_many_v); // Flow trait and tag template struct is_flow; // Tag template <> struct is_flow<> { using property_category = flow_category; }; // Trait template struct is_flow : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_flow_v = is_flow::value; PUSHMI_CONCEPT_DEF(template(class PS) concept Flow, is_flow_v); // Receiver trait and tag template struct is_receiver; // Tag template <> struct is_receiver<> { using property_category = receiver_category; }; // Trait template struct is_receiver : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_receiver_v = is_receiver::value; // PUSHMI_CONCEPT_DEF( // template (class PS) // concept Receiver, // is_receiver_v // ); // Sender trait and tag template struct is_sender; // Tag template <> struct is_sender<> { using property_category = sender_category; }; // Trait template struct is_sender : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_sender_v = is_sender::value; // PUSHMI_CONCEPT_DEF( // template (class PS) // concept Sender, // is_sender_v // ); // Executor trait and tag template struct is_executor; // Tag template <> struct is_executor<> { using property_category = executor_category; }; // Trait template struct is_executor : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_executor_v = is_executor::value; PUSHMI_CONCEPT_DEF( template(class PS) concept Executor, is_executor_v&& is_sender_v&& is_single_v); // Constrained trait and tag template struct is_constrained; // Tag template <> struct is_constrained<> : is_sender<> {}; // Trait template struct is_constrained : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_constrained_v = is_constrained::value; PUSHMI_CONCEPT_DEF( template(class PS) concept Constrained, is_constrained_v&& is_sender_v); // Time trait and tag template struct is_time; // Tag template <> struct is_time<> : is_constrained<> {}; // Trait template struct is_time : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_time_v = is_time::value; PUSHMI_CONCEPT_DEF( template(class PS) concept Time, is_time_v&& is_constrained_v&& is_sender_v); // AlwaysBlocking trait and tag template struct is_always_blocking; // Tag template <> struct is_always_blocking<> { using property_category = blocking_category; }; // Trait template struct is_always_blocking : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_always_blocking_v = is_always_blocking::value; PUSHMI_CONCEPT_DEF( template(class PS) concept AlwaysBlocking, is_always_blocking_v&& is_sender_v); // NeverBlocking trait and tag template struct is_never_blocking; // Tag template <> struct is_never_blocking<> { using property_category = blocking_category; }; // Trait template struct is_never_blocking : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_never_blocking_v = is_never_blocking::value; PUSHMI_CONCEPT_DEF( template(class PS) concept NeverBlocking, is_never_blocking_v&& is_sender_v); // MaybeBlocking trait and tag template struct is_maybe_blocking; // Tag template <> struct is_maybe_blocking<> { using property_category = blocking_category; }; // Trait template struct is_maybe_blocking : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_maybe_blocking_v = is_maybe_blocking::value; PUSHMI_CONCEPT_DEF( template(class PS) concept MaybeBlocking, is_maybe_blocking_v&& is_sender_v); // FifoSequence trait and tag template struct is_fifo_sequence; // Tag template <> struct is_fifo_sequence<> { using property_category = sequence_category; }; // Trait template struct is_fifo_sequence : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_fifo_sequence_v = is_fifo_sequence::value; PUSHMI_CONCEPT_DEF( template(class PS) concept FifoSequence, is_fifo_sequence_v&& is_sender_v); // ConcurrentSequence trait and tag template struct is_concurrent_sequence; // Tag template <> struct is_concurrent_sequence<> { using property_category = sequence_category; }; // Trait template struct is_concurrent_sequence : property_query> {}; template PUSHMI_INLINE_VAR constexpr bool is_concurrent_sequence_v = is_concurrent_sequence::value; PUSHMI_CONCEPT_DEF( template(class PS) concept ConcurrentSequence, is_concurrent_sequence_v&& is_sender_v); PUSHMI_CONCEPT_DEF( template(class R, class... PropertyN)(concept Receiver)(R, PropertyN...), requires(R& r)( ::pushmi::set_done(r), ::pushmi::set_error(r, std::exception_ptr{})) && SemiMovable && property_query_v && is_receiver_v && !is_sender_v); PUSHMI_CONCEPT_DEF( template(class R, class... VN)(concept ReceiveValue)(R, VN...), requires(R& r)(::pushmi::set_value(r, std::declval()...)) && Receiver && // GCC w/-fconcepts ICE on SemiMovable... True<> // And...> ); PUSHMI_CONCEPT_DEF( template(class R, class E = std::exception_ptr)(concept ReceiveError)(R, E), requires(R& r, E&& e)(::pushmi::set_error(r, (E &&) e)) && Receiver && SemiMovable); PUSHMI_CONCEPT_DEF( template(class D, class... PropertyN)(concept Sender)(D, PropertyN...), requires(D& d)( ::pushmi::executor(d), requires_>) && SemiMovable && Cardinality && property_query_v && is_sender_v && !is_receiver_v); PUSHMI_CONCEPT_DEF( template(class D, class S, class... PropertyN)( concept SenderTo)(D, S, PropertyN...), requires(D& d, S&& s)(::pushmi::submit(d, (S &&) s)) && Sender && Receiver && property_query_v); template PUSHMI_PP_CONSTRAINED_USING( Sender, executor_t =, decltype(::pushmi::executor(std::declval()))); // add concepts to support cancellation // PUSHMI_CONCEPT_DEF( template(class S, class... PropertyN)( concept FlowReceiver)(S, PropertyN...), Receiver&& property_query_v&& Flow); PUSHMI_CONCEPT_DEF( template(class R, class... VN)(concept FlowReceiveValue)(R, VN...), Flow&& ReceiveValue); PUSHMI_CONCEPT_DEF( template(class R, class E = std::exception_ptr)( concept FlowReceiveError)(R, E), Flow&& ReceiveError); PUSHMI_CONCEPT_DEF( template(class R, class Up)(concept FlowUpTo)(R, Up), requires(R& r, Up&& up)(::pushmi::set_starting(r, (Up &&) up)) && Flow); PUSHMI_CONCEPT_DEF( template(class S, class... PropertyN)(concept FlowSender)(S, PropertyN...), Sender&& property_query_v&& Flow); PUSHMI_CONCEPT_DEF( template(class D, class S, class... PropertyN)( concept FlowSenderTo)(D, S, PropertyN...), FlowSender&& property_query_v&& FlowReceiver); // add concepts for constraints // // the constraint could be time or priority enum or any other // ordering constraint value-type. // // top() returns the constraint value that will cause the item to run asap. // So now() for time and NORMAL for priority. // PUSHMI_CONCEPT_DEF( template(class D, class... PropertyN)( concept ConstrainedSender)(D, PropertyN...), requires(D& d)( ::pushmi::top(d), requires_>) && Sender && property_query_v && Constrained); PUSHMI_CONCEPT_DEF( template(class D, class S, class... PropertyN)( concept ConstrainedSenderTo)(D, S, PropertyN...), requires(D& d, S&& s)(::pushmi::submit(d, ::pushmi::top(d), (S &&) s)) && ConstrainedSender && property_query_v && Receiver); template PUSHMI_PP_CONSTRAINED_USING( ConstrainedSender, constraint_t =, decltype(::pushmi::top(std::declval()))); PUSHMI_CONCEPT_DEF( template(class D, class... PropertyN)(concept TimeSender)(D, PropertyN...), requires(D& d)( ::pushmi::now(d), requires_< Regular>) && ConstrainedSender && Time); PUSHMI_CONCEPT_DEF( template(class D, class S, class... PropertyN)( concept TimeSenderTo)(D, S, PropertyN...), ConstrainedSenderTo&& TimeSender); template PUSHMI_PP_CONSTRAINED_USING( TimeSender, time_point_t =, decltype(::pushmi::now(std::declval()))); } // namespace pushmi