DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (dcc6d7a0dc00)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_MaybeOneOf_h
#define mozilla_MaybeOneOf_h

#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/Move.h"
#include "mozilla/TemplateLib.h"

#include <new>    // For placement new

namespace mozilla {

/*
 * MaybeOneOf<T1, T2> is like Maybe, but it supports constructing either T1
 * or T2. When a MaybeOneOf<T1, T2> is constructed, it is |empty()|, i.e.,
 * no value has been constructed and no destructor will be called when the
 * MaybeOneOf<T1, T2> is destroyed. Upon calling |construct<T1>()| or
 * |construct<T2>()|, a T1 or T2 object will be constructed with the given
 * arguments and that object will be destroyed when the owning MaybeOneOf is
 * destroyed.
 */
template<class T1, class T2>
class MaybeOneOf
{
  AlignedStorage<tl::Max<sizeof(T1), sizeof(T2)>::value> storage;

  enum State { None, SomeT1, SomeT2 } state;
  template <class T, class Ignored = void> struct Type2State {};

  template <class T>
  T& as()
  {
    MOZ_ASSERT(state == Type2State<T>::result);
    return *(T*)storage.addr();
  }

  template <class T>
  const T& as() const
  {
    MOZ_ASSERT(state == Type2State<T>::result);
    return *(T*)storage.addr();
  }

public:
  MaybeOneOf() : state(None) {}
  ~MaybeOneOf() { destroyIfConstructed(); }

  MaybeOneOf(MaybeOneOf&& rhs)
    : state(None)
  {
    if (!rhs.empty()) {
      if (rhs.constructed<T1>()) {
        construct<T1>(Move(rhs.as<T1>()));
        rhs.as<T1>().~T1();
      } else {
        construct<T2>(Move(rhs.as<T2>()));
        rhs.as<T2>().~T2();
      }
      rhs.state = None;
    }
  }

  MaybeOneOf &operator=(MaybeOneOf&& rhs)
  {
    MOZ_ASSERT(this != &rhs, "Self-move is prohibited");
    this->~MaybeOneOf();
    new(this) MaybeOneOf(Move(rhs));
    return *this;
  }

  bool empty() const { return state == None; }

  template <class T>
  bool constructed() const { return state == Type2State<T>::result; }

  template <class T, class... Args>
  void construct(Args&&... aArgs)
  {
    MOZ_ASSERT(state == None);
    state = Type2State<T>::result;
    ::new (storage.addr()) T(Forward<Args>(aArgs)...);
  }

  template <class T>
  T& ref()
  {
    return as<T>();
  }

  template <class T>
  const T& ref() const
  {
    return as<T>();
  }

  void destroy()
  {
    MOZ_ASSERT(state == SomeT1 || state == SomeT2);
    if (state == SomeT1) {
      as<T1>().~T1();
    } else if (state == SomeT2) {
      as<T2>().~T2();
    }
    state = None;
  }

  void destroyIfConstructed()
  {
    if (!empty()) {
      destroy();
    }
  }

private:
  MaybeOneOf(const MaybeOneOf& aOther) = delete;
  const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete;
};

template <class T1, class T2>
template <class Ignored>
struct MaybeOneOf<T1, T2>::Type2State<T1, Ignored>
{
  typedef MaybeOneOf<T1, T2> Enclosing;
  static const typename Enclosing::State result = Enclosing::SomeT1;
};

template <class T1, class T2>
template <class Ignored>
struct MaybeOneOf<T1, T2>::Type2State<T2, Ignored>
{
  typedef MaybeOneOf<T1, T2> Enclosing;
  static const typename Enclosing::State result = Enclosing::SomeT2;
};

} // namespace mozilla

#endif /* mozilla_MaybeOneOf_h */