Loading...
/*
 * Copyright (c) 2022 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */
#ifndef __TRACED_VALUE__
#define __TRACED_VALUE__

// std
#include <memory>

namespace ld {

/// TracedValue wrapps  options with some default value that might be explicity
/// overwritten. The wrapper is constructed with `isDefault` flag set to true,
/// but whenever a new value is assigned to an existing wrapper instance
/// isDefault becomes false too.
template<typename Val>
struct TracedValue {

  protected:
  Val val;

  public:
  bool isDefault;

  TracedValue() = delete;
  constexpr TracedValue(Val val, bool isDefault = true) noexcept: val(std::move(val)), isDefault(isDefault) {}
  constexpr TracedValue(TracedValue&&) = default;
  constexpr TracedValue(const TracedValue&) = default;

  constexpr operator Val() const { return val; }
  constexpr Val get() const { return val; }

  constexpr TracedValue& operator=(TracedValue&& other)
  {
    val = std::move(other.val);
    isDefault = false;
    return *this;
  }

  constexpr TracedValue& operator=(const TracedValue& other)
  {
    val = other.val;
    isDefault = false;
    return *this;
  }

  constexpr TracedValue& operator=(Val newValue)
  {
    val = std::move(newValue);
    isDefault = false;
    return *this;
  }

  // Set new value without changing the isDefault flag.
  constexpr void overwrite(Val newDefault)
  {
    val = std::move(newDefault);
  }

  constexpr void overwrite(Val newVal, bool newIsDefault) {
    val = std::move(newVal);
    isDefault = std::move(newIsDefault);
  }
};

struct TracedBool: public TracedValue<bool> {

  TracedBool() = delete;
  constexpr TracedBool(bool val, bool isDefault = true): TracedValue(val, isDefault) {}

  constexpr operator bool() const { return val; }
  constexpr bool isForceOn() const { return !isDefault && val; }
  constexpr bool isForceOff() const { return !isDefault && !val; }
};
}
#endif // __TRACED_VALUE__