Bug 1597954 Comment 0 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

When working on dom/indexedDB, a class template that is initializable only once has shown to be useful to avoid usage errors and reduce the number of state assertions. It is based on `mozilla::Maybe` and exposes a small subset of its interface.

I feel this might be useful for other code as well, so it might be moved to MFBT. I can do this and add appropriate tests if this makes sense.

My initial version looks like this:
```
// A kind of mozilla::Maybe that can only be initialized and cleared once. It
// cannot be re-initialized. This is a more stateful than a const Maybe<T> in
// that it can be cleared, but much less stateful than a non-const Maybe<T>
// which could be reinitialized multiple times. Use with a const T to ensure
// that the contents cannot be modified either.
template <typename T, bool AllowLazy = false>
class InitializedOnce {
 public:
  template <typename Dummy = void>
  InitializedOnce(std::enable_if_t<AllowLazy, Dummy>* = nullptr) {}

  template <typename... Args>
  InitializedOnce(Args&&... aArgs)
      : mMaybe{Some(T{std::forward<Args>(aArgs)...})} {}

  template <typename... Args, typename Dummy = void>
  std::enable_if_t<AllowLazy, Dummy> init(Args&&... aArgs) {
    MOZ_ASSERT(mMaybe.isNothing());
    mMaybe.emplace(T{std::forward<Args>(aArgs)...});
  }

  explicit operator bool() const { return isSome(); }
  bool isSome() const { return mMaybe.isSome(); }
  bool isNothing() const { return mMaybe.isNothing(); }

  T& operator*() const { return *mMaybe; }
  T* operator->() const { return mMaybe.operator->(); }

  void reset() {
    MOZ_ASSERT(mMaybe.isSome());
    mMaybe.reset();
  }

 private:
  Maybe<T> mMaybe;
};
```
When working on dom/indexedDB, a class template that is initializable only once has shown to be useful to avoid usage errors and reduce the number of state assertions. It is based on `mozilla::Maybe` and exposes a small subset of its interface.

I feel this might be useful for other code as well, so it might be moved to MFBT. I can do this and add appropriate tests if this makes sense.

My initial version looks like this:
```
// A kind of mozilla::Maybe that can only be initialized and cleared once. It
// cannot be re-initialized. This is a more stateful than a const Maybe<T> in
// that it can be cleared, but much less stateful than a non-const Maybe<T>
// which could be reinitialized multiple times. Use with a const T to ensure
// that the contents cannot be modified either.
template <typename T, bool AllowLazy = false>
class InitializedOnce {
 public:
  template <typename Dummy = void>
  InitializedOnce(std::enable_if_t<AllowLazy, Dummy>* = nullptr) {}

  template <typename... Args>
  InitializedOnce(Args&&... aArgs)
      : mMaybe{Some(T{std::forward<Args>(aArgs)...})} {}

  InitializedOnce& operator=(const InitializedOnce&) = delete;
  InitializedOnce& operator=(InitializedOnce&&) = delete;

  template <typename... Args, typename Dummy = void>
  std::enable_if_t<AllowLazy, Dummy> init(Args&&... aArgs) {
    MOZ_ASSERT(mMaybe.isNothing());
    mMaybe.emplace(T{std::forward<Args>(aArgs)...});
  }

  explicit operator bool() const { return isSome(); }
  bool isSome() const { return mMaybe.isSome(); }
  bool isNothing() const { return mMaybe.isNothing(); }

  T& operator*() const { return *mMaybe; }
  T* operator->() const { return mMaybe.operator->(); }

  void reset() {
    MOZ_ASSERT(mMaybe.isSome());
    mMaybe.reset();
  }

 private:
  Maybe<T> mMaybe;
};
```

Back to Bug 1597954 Comment 0