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;
};
```
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)...})} {}
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;
};
```