Index: media/base/simple_state_machine.h |
diff --git a/media/base/simple_state_machine.h b/media/base/simple_state_machine.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e8aaaba56c7dc78af3bdd11f525f3be7ae4c7839 |
--- /dev/null |
+++ b/media/base/simple_state_machine.h |
@@ -0,0 +1,92 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef MEDIA_BASE_SIMPLE_STATE_MACHINE_H_ |
+#define MEDIA_BASE_SIMPLE_STATE_MACHINE_H_ |
+ |
+#include <tuple> |
+#include <type_traits> |
+ |
+#include "base/memory/ref_counted.h" |
+#include "media/base/media_export.h" |
+#include "media/base/state_machine.h" |
+ |
+namespace media { |
+ |
+// Convenient template for state machines that have all of their state provided |
+// during construction. Provides storage for each of the states, registers |
+// them with StateMachine, and provides a getter for them. |
+// |StateTypes| should be the raw type for a State subclass. These must be |
+// unique right now, unfortunately, for the provided Get template to work. We |
+// could work around this with an optional ordinal parameter in the getter. |
+template <typename... StateTypes> |
+class SimpleStateMachine : public StateMachine { |
+ public: |
+ SimpleStateMachine(scoped_refptr<StateTypes>... states) : states_(states...) { |
+ // Register all states with StateMachine. |
+ RegisterStates<0>(); |
+ } |
+ |
+ // Return the state of type |T|. |
+ template <typename T> |
+ T* Get() const { |
+ return FindElement<0, T>(); |
+ } |
+ |
+ private: |
+ typedef std::tuple<scoped_refptr<StateTypes>...> states_t; |
+ states_t states_; |
+ |
+ // Specialization to do nothing if we're asking for a state by index |
+ // that's more than we have. |
+ template <size_t pos> |
+ typename std::enable_if<pos >= std::tuple_size<states_t>::value>::type |
+ RegisterStates() {} |
+ |
+ // Specialization to register the |pos|-th state, and recurse to the |
+ // next one. |
+ template <size_t pos> |
+ typename std::enable_if < |
+ pos<std::tuple_size<states_t>::value>::type RegisterStates() { |
+ UsingState(std::get<pos>(states_)); |
+ RegisterStates<pos + 1>(); |
+ } |
+ |
+ // Check for type equality. |
+ // TODO: there has to be a better way. rewrite. |
+ template <typename T1, typename T2> |
+ struct is_same : std::false_type {}; |
+ template <typename T> |
+ struct is_same<T, T> : std::true_type {}; |
+ |
+ // When the element at |pos| is a scoped_refptr to |T|, return it as a |
+ // raw pointer. If we wanted to support duplicate types, then we should |
+ // also take an ordinal. If it's zero, then we return, else we recurse |
+ // on |pos+1| and |ordinal-1|. |
+ template <size_t pos, typename T> |
+ typename std::enable_if < |
+ pos<std::tuple_size<states_t>::value && |
+ is_same<typename std::tuple_element<pos, states_t>::type, |
+ scoped_refptr<T>>::value, |
+ T*>::type |
+ FindElement() const { |
+ return std::get<pos>(states_).get(); |
+ } |
+ |
+ // Continue searching for an element of type |scoped_refptr<T>| if the |
+ // |pos|-th element doesn't match. |
+ template <size_t pos, typename T> |
+ typename std::enable_if < |
+ pos<std::tuple_size<states_t>::value && |
+ !is_same<typename std::tuple_element<pos, states_t>::type, |
+ scoped_refptr<T>>::value, |
+ T*>::type |
+ FindElement() const { |
+ return FindElement<pos + 1, T>(); |
+ } |
+}; |
+ |
+} // namespace media |
+ |
+#endif // MEDIA_BASE_SIMPLE_STATE_MACHINE_H_ |