|  | @@ -16,12 +16,15 @@
 | 
	
		
			
				|  |  |  #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
 | 
	
		
			
				|  |  |  #define ABSL_FLAGS_INTERNAL_FLAG_H_
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <atomic>
 | 
	
		
			
				|  |  |  #include <cstring>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "absl/base/thread_annotations.h"
 | 
	
		
			
				|  |  |  #include "absl/flags/internal/commandlineflag.h"
 | 
	
		
			
				|  |  |  #include "absl/flags/internal/registry.h"
 | 
	
		
			
				|  |  |  #include "absl/memory/memory.h"
 | 
	
		
			
				|  |  |  #include "absl/strings/str_cat.h"
 | 
	
		
			
				|  |  | +#include "absl/synchronization/mutex.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace absl {
 | 
	
		
			
				|  |  |  namespace flags_internal {
 | 
	
	
		
			
				|  | @@ -66,6 +69,124 @@ using FlagCallback = void (*)();
 | 
	
		
			
				|  |  |  void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
 | 
	
		
			
				|  |  |                      FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// The class encapsulates the Flag's data and safe access to it.
 | 
	
		
			
				|  |  | +class FlagImpl {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  constexpr FlagImpl(const flags_internal::FlagOpFn op,
 | 
	
		
			
				|  |  | +                     const flags_internal::FlagMarshallingOpFn marshalling_op,
 | 
	
		
			
				|  |  | +                     const flags_internal::InitialValGenFunc initial_value_gen)
 | 
	
		
			
				|  |  | +      : op_(op),
 | 
	
		
			
				|  |  | +        marshalling_op_(marshalling_op),
 | 
	
		
			
				|  |  | +        initial_value_gen_(initial_value_gen) {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Forces destruction of the Flag's data.
 | 
	
		
			
				|  |  | +  void Destroy() const;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Constant access methods
 | 
	
		
			
				|  |  | +  bool IsModified() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  void Read(const CommandLineFlag& flag, void* dst,
 | 
	
		
			
				|  |  | +            const flags_internal::FlagOpFn dst_op) const
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  // Attempts to parse supplied `value` std::string.
 | 
	
		
			
				|  |  | +  bool TryParse(const CommandLineFlag& flag, void* dst, absl::string_view value,
 | 
	
		
			
				|  |  | +                std::string* err) const
 | 
	
		
			
				|  |  | +      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  template <typename T>
 | 
	
		
			
				|  |  | +  bool AtomicGet(T* v) const {
 | 
	
		
			
				|  |  | +    const int64_t r = atomic_.load(std::memory_order_acquire);
 | 
	
		
			
				|  |  | +    if (r != flags_internal::AtomicInit()) {
 | 
	
		
			
				|  |  | +      std::memcpy(v, &r, sizeof(T));
 | 
	
		
			
				|  |  | +      return true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return false;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Mutating access methods
 | 
	
		
			
				|  |  | +  void Write(const CommandLineFlag& flag, const void* src,
 | 
	
		
			
				|  |  | +             const flags_internal::FlagOpFn src_op)
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  bool SetFromString(const CommandLineFlag& flag, absl::string_view value,
 | 
	
		
			
				|  |  | +                     FlagSettingMode set_mode, ValueSource source,
 | 
	
		
			
				|  |  | +                     std::string* err) ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  // If possible, updates copy of the Flag's value that is stored in an
 | 
	
		
			
				|  |  | +  // atomic word.
 | 
	
		
			
				|  |  | +  void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Interfaces to operate on callbacks.
 | 
	
		
			
				|  |  | +  void SetCallback(const flags_internal::FlagCallback mutation_callback)
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Interfaces to save/restore mutable flag data
 | 
	
		
			
				|  |  | +  template <typename T>
 | 
	
		
			
				|  |  | +  std::unique_ptr<flags_internal::FlagStateInterface> SaveState(
 | 
	
		
			
				|  |  | +      Flag<T>* flag) const ABSL_LOCKS_EXCLUDED(locks_->primary_mu) {
 | 
	
		
			
				|  |  | +    T&& cur_value = flag->Get();
 | 
	
		
			
				|  |  | +    absl::MutexLock l(DataGuard());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return absl::make_unique<flags_internal::FlagState<T>>(
 | 
	
		
			
				|  |  | +        flag, std::move(cur_value), modified_, on_command_line_, counter_);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  bool RestoreState(const CommandLineFlag& flag, const void* value,
 | 
	
		
			
				|  |  | +                    bool modified, bool on_command_line, int64_t counter)
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Value validation interfaces.
 | 
	
		
			
				|  |  | +  void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag) const
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +  bool ValidateInputValue(absl::string_view value) const
 | 
	
		
			
				|  |  | +      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  // Lazy initialization of the Flag's data.
 | 
	
		
			
				|  |  | +  void Init();
 | 
	
		
			
				|  |  | +  // Ensures that the lazily initialized data is initialized,
 | 
	
		
			
				|  |  | +  // and returns pointer to the mutex guarding flags data.
 | 
	
		
			
				|  |  | +  absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED(locks_->primary_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Immutable Flag's data.
 | 
	
		
			
				|  |  | +  const FlagOpFn op_;                          // Type-specific handler
 | 
	
		
			
				|  |  | +  const FlagMarshallingOpFn marshalling_op_;   // Marshalling ops handler
 | 
	
		
			
				|  |  | +  const InitialValGenFunc initial_value_gen_;  // Makes flag's initial value
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Mutable Flag's data. (guarded by locks_->primary_mu).
 | 
	
		
			
				|  |  | +  // Indicates that locks_, cur_ and def_ fields have been lazily initialized.
 | 
	
		
			
				|  |  | +  std::atomic<bool> inited_{false};
 | 
	
		
			
				|  |  | +  // Has flag value been modified?
 | 
	
		
			
				|  |  | +  bool modified_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
 | 
	
		
			
				|  |  | +  // Specified on command line.
 | 
	
		
			
				|  |  | +  bool on_command_line_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
 | 
	
		
			
				|  |  | +  // Lazily initialized pointer to default value
 | 
	
		
			
				|  |  | +  void* def_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
 | 
	
		
			
				|  |  | +  // Lazily initialized pointer to current value
 | 
	
		
			
				|  |  | +  void* cur_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
 | 
	
		
			
				|  |  | +  // Mutation counter
 | 
	
		
			
				|  |  | +  int64_t counter_ ABSL_GUARDED_BY(locks_->primary_mu) = 0;
 | 
	
		
			
				|  |  | +  // For some types, a copy of the current value is kept in an atomically
 | 
	
		
			
				|  |  | +  // accessible field.
 | 
	
		
			
				|  |  | +  std::atomic<int64_t> atomic_{flags_internal::AtomicInit()};
 | 
	
		
			
				|  |  | +  // Mutation callback
 | 
	
		
			
				|  |  | +  FlagCallback callback_ = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Lazily initialized mutexes for this flag value.  We cannot inline a
 | 
	
		
			
				|  |  | +  // SpinLock or Mutex here because those have non-constexpr constructors and
 | 
	
		
			
				|  |  | +  // so would prevent constant initialization of this type.
 | 
	
		
			
				|  |  | +  // TODO(rogeeff): fix it once Mutex has constexpr constructor
 | 
	
		
			
				|  |  | +  // The following struct contains the locks in a CommandLineFlag struct.
 | 
	
		
			
				|  |  | +  // They are in a separate struct that is lazily allocated to avoid problems
 | 
	
		
			
				|  |  | +  // with static initialization and to avoid multiple allocations.
 | 
	
		
			
				|  |  | +  struct CommandLineFlagLocks {
 | 
	
		
			
				|  |  | +    absl::Mutex primary_mu;   // protects several fields in CommandLineFlag
 | 
	
		
			
				|  |  | +    absl::Mutex callback_mu;  // used to serialize callbacks
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  CommandLineFlagLocks* locks_ = nullptr;  // locks, laziliy allocated.
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // This is "unspecified" implementation of absl::Flag<T> type.
 | 
	
		
			
				|  |  |  template <typename T>
 | 
	
		
			
				|  |  |  class Flag final : public flags_internal::CommandLineFlag {
 | 
	
	
		
			
				|  | @@ -76,30 +197,11 @@ class Flag final : public flags_internal::CommandLineFlag {
 | 
	
		
			
				|  |  |                   const flags_internal::InitialValGenFunc initial_value_gen)
 | 
	
		
			
				|  |  |        : flags_internal::CommandLineFlag(
 | 
	
		
			
				|  |  |              name, flags_internal::HelpText::FromFunctionPointer(help_gen),
 | 
	
		
			
				|  |  | -            filename, &flags_internal::FlagOps<T>, marshalling_op,
 | 
	
		
			
				|  |  | -            initial_value_gen,
 | 
	
		
			
				|  |  | -            /*def=*/nullptr,
 | 
	
		
			
				|  |  | -            /*cur=*/nullptr),
 | 
	
		
			
				|  |  | -        atomic_(flags_internal::AtomicInit()),
 | 
	
		
			
				|  |  | -        callback_(nullptr) {}
 | 
	
		
			
				|  |  | +            filename),
 | 
	
		
			
				|  |  | +        impl_(&flags_internal::FlagOps<T>, marshalling_op, initial_value_gen) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    T Get() const {
 | 
	
		
			
				|  |  | -    // Implementation notes:
 | 
	
		
			
				|  |  | -    //
 | 
	
		
			
				|  |  | -    // We are wrapping a union around the value of `T` to serve three purposes:
 | 
	
		
			
				|  |  | -    //
 | 
	
		
			
				|  |  | -    //  1. `U.value` has correct size and alignment for a value of type `T`
 | 
	
		
			
				|  |  | -    //  2. The `U.value` constructor is not invoked since U's constructor does
 | 
	
		
			
				|  |  | -    //  not
 | 
	
		
			
				|  |  | -    //     do it explicitly.
 | 
	
		
			
				|  |  | -    //  3. The `U.value` destructor is invoked since U's destructor does it
 | 
	
		
			
				|  |  | -    //     explicitly. This makes `U` a kind of RAII wrapper around non default
 | 
	
		
			
				|  |  | -    //     constructible value of T, which is destructed when we leave the
 | 
	
		
			
				|  |  | -    //     scope. We do need to destroy U.value, which is constructed by
 | 
	
		
			
				|  |  | -    //     CommandLineFlag::Read even though we left it in a moved-from state
 | 
	
		
			
				|  |  | -    //     after std::move.
 | 
	
		
			
				|  |  | -    //
 | 
	
		
			
				|  |  | -    // All of this serves to avoid requiring `T` being default constructible.
 | 
	
		
			
				|  |  | +    // See implementation notes in CommandLineFlag::Get().
 | 
	
		
			
				|  |  |      union U {
 | 
	
		
			
				|  |  |        T value;
 | 
	
		
			
				|  |  |        U() {}
 | 
	
	
		
			
				|  | @@ -107,89 +209,70 @@ class Flag final : public flags_internal::CommandLineFlag {
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |      U u;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    Read(&u.value, &flags_internal::FlagOps<T>);
 | 
	
		
			
				|  |  | +    impl_.Read(*this, &u.value, &flags_internal::FlagOps<T>);
 | 
	
		
			
				|  |  |      return std::move(u.value);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  bool AtomicGet(T* v) const {
 | 
	
		
			
				|  |  | -    const int64_t r = atomic_.load(std::memory_order_acquire);
 | 
	
		
			
				|  |  | -    if (r != flags_internal::AtomicInit()) {
 | 
	
		
			
				|  |  | -      std::memcpy(v, &r, sizeof(T));
 | 
	
		
			
				|  |  | -      return true;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return false;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  bool AtomicGet(T* v) const { return impl_.AtomicGet(v); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  void Set(const T& v) { Write(&v, &flags_internal::FlagOps<T>); }
 | 
	
		
			
				|  |  | +  void Set(const T& v) { impl_.Write(*this, &v, &flags_internal::FlagOps<T>); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void SetCallback(const flags_internal::FlagCallback mutation_callback) {
 | 
	
		
			
				|  |  | -    absl::MutexLock l(InitFlagIfNecessary());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    callback_ = mutation_callback;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    InvokeCallback();
 | 
	
		
			
				|  |  | +    impl_.SetCallback(mutation_callback);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -  friend class FlagState<T>;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  void Destroy() const override {
 | 
	
		
			
				|  |  | -    // Values are heap allocated for Abseil Flags.
 | 
	
		
			
				|  |  | -    if (cur_) Delete(op_, cur_);
 | 
	
		
			
				|  |  | -    if (def_) Delete(op_, def_);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    delete locks_;
 | 
	
		
			
				|  |  | +  // CommandLineFlag interface
 | 
	
		
			
				|  |  | +  bool IsModified() const override { return impl_.IsModified(); }
 | 
	
		
			
				|  |  | +  bool IsSpecifiedOnCommandLine() const override {
 | 
	
		
			
				|  |  | +    return impl_.IsSpecifiedOnCommandLine();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  std::string DefaultValue() const override { return impl_.DefaultValue(); }
 | 
	
		
			
				|  |  | +  std::string CurrentValue() const override { return impl_.CurrentValue(); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  void StoreAtomic() override {
 | 
	
		
			
				|  |  | -    if (sizeof(T) <= sizeof(int64_t)) {
 | 
	
		
			
				|  |  | -      int64_t t = 0;
 | 
	
		
			
				|  |  | -      std::memcpy(&t, cur_, (std::min)(sizeof(T), sizeof(int64_t)));
 | 
	
		
			
				|  |  | -      atomic_.store(t, std::memory_order_release);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +  bool ValidateInputValue(absl::string_view value) const override {
 | 
	
		
			
				|  |  | +    return impl_.ValidateInputValue(value);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Interfaces to save and restore flags to/from persistent state.
 | 
	
		
			
				|  |  |    // Returns current flag state or nullptr if flag does not support
 | 
	
		
			
				|  |  |    // saving and restoring a state.
 | 
	
		
			
				|  |  |    std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
 | 
	
		
			
				|  |  | -    T curr_value = Get();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    absl::MutexLock l(InitFlagIfNecessary());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return absl::make_unique<flags_internal::FlagState<T>>(
 | 
	
		
			
				|  |  | -        this, std::move(curr_value), modified_, on_command_line_, counter_);
 | 
	
		
			
				|  |  | +    return impl_.SaveState(this);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Restores the flag state to the supplied state object. If there is
 | 
	
		
			
				|  |  |    // nothing to restore returns false. Otherwise returns true.
 | 
	
		
			
				|  |  |    bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
 | 
	
		
			
				|  |  | -    if (MutationCounter() == flag_state.counter_) return false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    Set(flag_state.cur_value_);
 | 
	
		
			
				|  |  | +    return impl_.RestoreState(*this, &flag_state.cur_value_,
 | 
	
		
			
				|  |  | +                              flag_state.modified_, flag_state.on_command_line_,
 | 
	
		
			
				|  |  | +                              flag_state.counter_);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // Race condition here? This should disappear once we move the rest of the
 | 
	
		
			
				|  |  | -    // flag's data into Flag's internals.
 | 
	
		
			
				|  |  | +  bool SetFromString(absl::string_view value,
 | 
	
		
			
				|  |  | +                     flags_internal::FlagSettingMode set_mode,
 | 
	
		
			
				|  |  | +                     flags_internal::ValueSource source,
 | 
	
		
			
				|  |  | +                     std::string* error) override {
 | 
	
		
			
				|  |  | +    return impl_.SetFromString(*this, value, set_mode, source, error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    absl::MutexLock l(InitFlagIfNecessary());
 | 
	
		
			
				|  |  | -    modified_ = flag_state.modified_;
 | 
	
		
			
				|  |  | -    on_command_line_ = flag_state.on_command_line_;
 | 
	
		
			
				|  |  | -    return true;
 | 
	
		
			
				|  |  | +  void CheckDefaultValueParsingRoundtrip() const override {
 | 
	
		
			
				|  |  | +    impl_.CheckDefaultValueParsingRoundtrip(*this);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // Interfaces to overate on callbacks.
 | 
	
		
			
				|  |  | -  void InvokeCallback() override
 | 
	
		
			
				|  |  | -      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
 | 
	
		
			
				|  |  | -    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
 | 
	
		
			
				|  |  | -                                   callback_);
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  friend class FlagState<T>;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void Destroy() const override { impl_.Destroy(); }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void Read(void* dst) const override {
 | 
	
		
			
				|  |  | +    impl_.Read(*this, dst, &flags_internal::FlagOps<T>);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  flags_internal::FlagOpFn TypeId() const override {
 | 
	
		
			
				|  |  | +    return &flags_internal::FlagOps<T>;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Flag's data
 | 
	
		
			
				|  |  | -  // For some types, a copy of the current value is kept in an atomically
 | 
	
		
			
				|  |  | -  // accessible field.
 | 
	
		
			
				|  |  | -  std::atomic<int64_t> atomic_;
 | 
	
		
			
				|  |  | -  FlagCallback callback_;  // Mutation callback
 | 
	
		
			
				|  |  | +  FlagImpl impl_;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  template <typename T>
 |