blob: 66edb89113806fe5b28f85b4c51c159e50ed332c [file] [log] [blame]
// Copyright 2014 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 MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
#define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
#include <cstddef>
#include <memory>
#include <new>
#include "mojo/public/cpp/bindings/type_converter.h"
#include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/macros.h"
namespace mojo {
namespace internal {
template <typename Struct>
class StructHelper {
public:
template <typename Ptr>
static void Initialize(Ptr* ptr) {
ptr->Initialize();
}
};
} // namespace internal
// Smart pointer wrapping a mojom structure or union, with move-only semantics.
template <typename Struct>
class StructPtr {
public:
StructPtr() {}
StructPtr(std::nullptr_t) {}
~StructPtr() {}
StructPtr& operator=(std::nullptr_t) {
reset();
return *this;
}
StructPtr(StructPtr&& other) { Take(&other); }
StructPtr& operator=(StructPtr&& other) {
Take(&other);
return *this;
}
template <typename U>
U To() const {
return TypeConverter<U, StructPtr>::Convert(*this);
}
void reset() { ptr_.reset(); }
// Tests as true if non-null, false if null.
explicit operator bool() const { return !!ptr_; }
bool is_null() const { return !ptr_; }
Struct& operator*() const {
MOJO_DCHECK(ptr_);
return *ptr_;
}
Struct* operator->() const {
MOJO_DCHECK(ptr_);
return ptr_.get();
}
Struct* get() const { return ptr_.get(); }
void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); }
// Please note that calling this method will fail compilation if the value
// type |Struct| doesn't have a Clone() method defined (which usually means
// that it contains Mojo handles).
StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); }
bool Equals(const StructPtr& other) const {
if (is_null() || other.is_null())
return is_null() && other.is_null();
return ptr_->Equals(*other.ptr_);
}
private:
friend class internal::StructHelper<Struct>;
void Initialize() {
MOJO_DCHECK(!ptr_);
ptr_.reset(new Struct());
}
void Take(StructPtr* other) {
reset();
Swap(other);
}
std::unique_ptr<Struct> ptr_;
MOJO_MOVE_ONLY_TYPE(StructPtr);
};
// Designed to be used when Struct is small and copyable. Unions are always
// InlinedStructPtr in practice.
template <typename Struct>
class InlinedStructPtr {
public:
InlinedStructPtr() : is_null_(true) {}
InlinedStructPtr(std::nullptr_t) : is_null_(true) {}
~InlinedStructPtr() {}
InlinedStructPtr& operator=(std::nullptr_t) {
reset();
return *this;
}
InlinedStructPtr(InlinedStructPtr&& other) : is_null_(true) { Take(&other); }
InlinedStructPtr& operator=(InlinedStructPtr&& other) {
Take(&other);
return *this;
}
template <typename U>
U To() const {
return TypeConverter<U, InlinedStructPtr>::Convert(*this);
}
void reset() {
is_null_ = true;
value_. ~Struct();
new (&value_) Struct();
}
// Tests as true if non-null, false if null.
explicit operator bool() const { return !is_null_; }
bool is_null() const { return is_null_; }
Struct& operator*() const {
MOJO_DCHECK(!is_null_);
return value_;
}
Struct* operator->() const {
MOJO_DCHECK(!is_null_);
return &value_;
}
Struct* get() const { return is_null() ? nullptr : &value_; }
void Swap(InlinedStructPtr* other) {
std::swap(value_, other->value_);
std::swap(is_null_, other->is_null_);
}
InlinedStructPtr Clone() const {
return is_null() ? InlinedStructPtr() : value_.Clone();
}
bool Equals(const InlinedStructPtr& other) const {
if (is_null() || other.is_null())
return is_null() && other.is_null();
return value_.Equals(other.value_);
}
private:
friend class internal::StructHelper<Struct>;
void Initialize() { is_null_ = false; }
void Take(InlinedStructPtr* other) {
reset();
Swap(other);
}
mutable Struct value_;
bool is_null_;
MOJO_MOVE_ONLY_TYPE(InlinedStructPtr);
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_