// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // View class template for enums. #ifndef EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_ #define EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_ #include #include #include #include #include "runtime/cpp/emboss_defines.h" #include "runtime/cpp/emboss_view_parameters.h" // Forward declarations for optional text processing helpers. namespace emboss { class TextOutputOptions; namespace support { template bool ReadEnumViewFromTextStream(View *view, Stream *stream); template void WriteEnumViewToTextStream(View *view, Stream *stream, const TextOutputOptions &options); } // namespace support } // namespace emboss namespace emboss { namespace support { // EnumView is a view for Enums inside of bitfields. template class EnumView final { public: using ValueType = typename ::std::remove_cv::type; static_assert( Parameters::kBits <= sizeof(ValueType) * 8, "EnumView requires sizeof(ValueType) * 8 >= Parameters::kBits."); template explicit EnumView(Args &&...args) : buffer_{::std::forward(args)...} {} EnumView() : buffer_() {} EnumView(const EnumView &) = default; EnumView(EnumView &&) = default; EnumView &operator=(const EnumView &) = default; EnumView &operator=(EnumView &&) = default; ~EnumView() = default; // TODO(bolms): Here and in CouldWriteValue(), the static_casts to ValueType // rely on implementation-defined behavior when ValueType is signed. ValueType Read() const { ValueType result = static_cast(buffer_.ReadUInt()); EMBOSS_CHECK(Parameters::ValueIsOk(result)); return result; } ValueType UncheckedRead() const { return static_cast(buffer_.UncheckedReadUInt()); } void Write(ValueType value) const { const bool result = TryToWrite(value); (void)result; EMBOSS_CHECK(result); } bool TryToWrite(ValueType value) const { if (!CouldWriteValue(value)) return false; if (!IsComplete()) return false; buffer_.WriteUInt(static_cast(value)); return true; } static constexpr bool CouldWriteValue(ValueType value) { // The value can be written if: // // a) it can fit in BitViewType::ValueType (verified by casting to // BitViewType::ValueType and back, and making sure that the value is // unchanged) // // and either: // // b1) the field size is large enough to hold all values, or // b2) the value is less than 2**(field size in bits) return value == static_cast( static_cast(value)) && ((Parameters::kBits == sizeof(typename BitViewType::ValueType) * 8) || (static_cast(value) < ((static_cast(1) << (Parameters::kBits - 1)) << 1))) && Parameters::ValueIsOk(value); } void UncheckedWrite(ValueType value) const { buffer_.UncheckedWriteUInt( static_cast(value)); } template void CopyFrom(const OtherView &other) const { Write(other.Read()); } template void UncheckedCopyFrom(const OtherView &other) const { UncheckedWrite(other.UncheckedRead()); } template bool TryToCopyFrom(const OtherView &other) const { return other.Ok() && TryToWrite(other.Read()); } // All bit patterns in the underlying buffer are valid, so Ok() is always // true if IsComplete() is true. bool Ok() const { return IsComplete() && Parameters::ValueIsOk(UncheckedRead()); } template bool Equals(const EnumView &other) const { return Read() == other.Read(); } template bool UncheckedEquals( const EnumView &other) const { return UncheckedRead() == other.UncheckedRead(); } bool IsComplete() const { return buffer_.Ok() && buffer_.SizeInBits() >= Parameters::kBits; } template bool UpdateFromTextStream(Stream *stream) const { return ::emboss::support::ReadEnumViewFromTextStream(this, stream); } template void WriteToTextStream(Stream *stream, const TextOutputOptions &options) const { ::emboss::support::WriteEnumViewToTextStream(this, stream, options); } static constexpr bool IsAggregate() { return false; } static constexpr int SizeInBits() { return Parameters::kBits; } private: BitViewType buffer_; }; } // namespace support } // namespace emboss #endif // EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_