Sealable: fixed semantic; atomic type for the flag variable

Summary:
* Fixed semantic: all kinds of derivative instances lose `sealed` flag (which is expected);
 * Using atomic<bool> for `sealed_` ivar.

Reviewed By: fkgozali

Differential Revision: D7230674

fbshipit-source-id: abe786610c20a45a0fabb9068120e24adeeeac7f
This commit is contained in:
Valentin Shergin 2018-03-18 19:04:08 -07:00 committed by Facebook Github Bot
parent 1c53471911
commit d16772a31e
2 changed files with 49 additions and 6 deletions

View File

@ -12,6 +12,36 @@
namespace facebook { namespace facebook {
namespace react { namespace react {
/*
* Note:
* We must explictly implement all *the rule of five* methods because:
* 1. Using `std::atomic` behind `sealed_` implicitly deletes default
* constructors;
* 2. We have to establish behaviour where any new cloned or moved instances
* of the object lose `sealed` flag.
*
* See more about the rule of three/five/zero:
* http://en.cppreference.com/w/cpp/language/rule_of_three
*/
Sealable::Sealable(): sealed_(false) {}
Sealable::Sealable(const Sealable& other): sealed_(false) {};
Sealable::Sealable(Sealable&& other) noexcept: sealed_(false) {};
Sealable::~Sealable() noexcept {};
Sealable& Sealable::operator= (const Sealable& other) {
ensureUnsealed();
return *this;
}
Sealable& Sealable::operator= (Sealable&& other) noexcept {
ensureUnsealed();
return *this;
};
void Sealable::seal() const { void Sealable::seal() const {
sealed_ = true; sealed_ = true;
} }

View File

@ -7,21 +7,27 @@
#pragma once #pragma once
#import <atomic>
namespace facebook { namespace facebook {
namespace react { namespace react {
/* /*
* Represents something which can be *sealed* (imperatively marked as immutable). * Represents an object which can be *sealed* (imperatively marked as immutable).
*
* The `sealed` flag is tight to a particular instance of the class and resets
* to `false` for all newly created (by copy-constructor, assignment operator
* and so on) derivative objects.
* *
* Why do we need this? In Fabric, some objects are semi-immutable * Why do we need this? In Fabric, some objects are semi-immutable
* even if they explicitly marked as `const`. It means that in some special * even if they are explicitly marked as `const`. It means that in some special
* cases those objects can be const-cast-away and then mutated. That comes from * cases those objects can be const-casted-away and then mutated. That comes from
* the fact that we share some object's life-cycle responsibilities with React * the fact that we share some object's life-cycle responsibilities with React
* and the immutability is guaranteed by some logic splitted between native and * and the immutability is guaranteed by some logic splitted between native and
* JavaScript worlds (which makes impossible to fully use immutability * JavaScript worlds (which makes it impossible to fully use immutability
* enforcement at a language level). * enforcement at a language level).
* To detect possible errors as early as possible we additionally mark objects * To detect possible errors as early as possible we additionally mark objects
* as *sealed* after some stage and then enforce this at run-time. * as *sealed* after some stages and then enforce this at run-time.
* *
* How to use: * How to use:
* 1. Inherit your class from `Sealable`. * 1. Inherit your class from `Sealable`.
@ -31,6 +37,13 @@ namespace react {
*/ */
class Sealable { class Sealable {
public: public:
Sealable();
Sealable(const Sealable& other);
Sealable(Sealable&& other) noexcept;
~Sealable() noexcept;
Sealable& operator=(const Sealable& other);
Sealable& operator=(Sealable&& other) noexcept;
/* /*
* Seals the object. This operation is irreversible; * Seals the object. This operation is irreversible;
* the object cannot be "unsealed" after being sealing. * the object cannot be "unsealed" after being sealing.
@ -50,7 +63,7 @@ protected:
void ensureUnsealed() const; void ensureUnsealed() const;
private: private:
mutable bool sealed_ {false}; mutable std::atomic<bool> sealed_ {false};
}; };
} // namespace react } // namespace react