1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // View class template for enums. 16 #ifndef EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_ 17 #define EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_ 18 19 #include <cctype> 20 #include <cstdint> 21 #include <string> 22 #include <utility> 23 24 #include "runtime/cpp/emboss_defines.h" 25 #include "runtime/cpp/emboss_view_parameters.h" 26 27 // Forward declarations for optional text processing helpers. 28 namespace emboss { 29 class TextOutputOptions; 30 namespace support { 31 template <class Stream, class View> 32 bool ReadEnumViewFromTextStream(View *view, Stream *stream); 33 template <class Stream, class View> 34 void WriteEnumViewToTextStream(View *view, Stream *stream, 35 const TextOutputOptions &options); 36 } // namespace support 37 } // namespace emboss 38 39 namespace emboss { 40 namespace support { 41 42 // EnumView is a view for Enums inside of bitfields. 43 template <class Enum, class Parameters, class BitViewType> 44 class EnumView final { 45 public: 46 using ValueType = typename ::std::remove_cv<Enum>::type; 47 static_assert( 48 Parameters::kBits <= sizeof(ValueType) * 8, 49 "EnumView requires sizeof(ValueType) * 8 >= Parameters::kBits."); 50 template <typename... Args> EnumView(Args &&...args)51 explicit EnumView(Args &&...args) : buffer_{::std::forward<Args>(args)...} {} EnumView()52 EnumView() : buffer_() {} 53 EnumView(const EnumView &) = default; 54 EnumView(EnumView &&) = default; 55 EnumView &operator=(const EnumView &) = default; 56 EnumView &operator=(EnumView &&) = default; 57 ~EnumView() = default; 58 59 // TODO(bolms): Here and in CouldWriteValue(), the static_casts to ValueType 60 // rely on implementation-defined behavior when ValueType is signed. Read()61 ValueType Read() const { 62 ValueType result = static_cast<ValueType>(buffer_.ReadUInt()); 63 EMBOSS_CHECK(Parameters::ValueIsOk(result)); 64 return result; 65 } UncheckedRead()66 ValueType UncheckedRead() const { 67 return static_cast<ValueType>(buffer_.UncheckedReadUInt()); 68 } Write(ValueType value)69 void Write(ValueType value) const { 70 const bool result = TryToWrite(value); 71 (void)result; 72 EMBOSS_CHECK(result); 73 } TryToWrite(ValueType value)74 bool TryToWrite(ValueType value) const { 75 if (!CouldWriteValue(value)) return false; 76 if (!IsComplete()) return false; 77 buffer_.WriteUInt(static_cast<typename BitViewType::ValueType>(value)); 78 return true; 79 } CouldWriteValue(ValueType value)80 static constexpr bool CouldWriteValue(ValueType value) { 81 // The value can be written if: 82 // 83 // a) it can fit in BitViewType::ValueType (verified by casting to 84 // BitViewType::ValueType and back, and making sure that the value is 85 // unchanged) 86 // 87 // and either: 88 // 89 // b1) the field size is large enough to hold all values, or 90 // b2) the value is less than 2**(field size in bits) 91 return value == static_cast<ValueType>( 92 static_cast<typename BitViewType::ValueType>(value)) && 93 ((Parameters::kBits == 94 sizeof(typename BitViewType::ValueType) * 8) || 95 (static_cast<typename BitViewType::ValueType>(value) < 96 ((static_cast<typename BitViewType::ValueType>(1) 97 << (Parameters::kBits - 1)) 98 << 1))) && 99 Parameters::ValueIsOk(value); 100 } UncheckedWrite(ValueType value)101 void UncheckedWrite(ValueType value) const { 102 buffer_.UncheckedWriteUInt( 103 static_cast<typename BitViewType::ValueType>(value)); 104 } 105 106 template <typename OtherView> CopyFrom(const OtherView & other)107 void CopyFrom(const OtherView &other) const { 108 Write(other.Read()); 109 } 110 template <typename OtherView> UncheckedCopyFrom(const OtherView & other)111 void UncheckedCopyFrom(const OtherView &other) const { 112 UncheckedWrite(other.UncheckedRead()); 113 } 114 template <typename OtherView> TryToCopyFrom(const OtherView & other)115 bool TryToCopyFrom(const OtherView &other) const { 116 return other.Ok() && TryToWrite(other.Read()); 117 } 118 119 // All bit patterns in the underlying buffer are valid, so Ok() is always 120 // true if IsComplete() is true. Ok()121 bool Ok() const { 122 return IsComplete() && Parameters::ValueIsOk(UncheckedRead()); 123 } 124 template <class OtherBitViewType> Equals(const EnumView<Enum,Parameters,OtherBitViewType> & other)125 bool Equals(const EnumView<Enum, Parameters, OtherBitViewType> &other) const { 126 return Read() == other.Read(); 127 } 128 template <class OtherBitViewType> UncheckedEquals(const EnumView<Enum,Parameters,OtherBitViewType> & other)129 bool UncheckedEquals( 130 const EnumView<Enum, Parameters, OtherBitViewType> &other) const { 131 return UncheckedRead() == other.UncheckedRead(); 132 } IsComplete()133 bool IsComplete() const { 134 return buffer_.Ok() && buffer_.SizeInBits() >= Parameters::kBits; 135 } 136 137 template <class Stream> UpdateFromTextStream(Stream * stream)138 bool UpdateFromTextStream(Stream *stream) const { 139 return ::emboss::support::ReadEnumViewFromTextStream(this, stream); 140 } 141 142 template <class Stream> WriteToTextStream(Stream * stream,const TextOutputOptions & options)143 void WriteToTextStream(Stream *stream, 144 const TextOutputOptions &options) const { 145 ::emboss::support::WriteEnumViewToTextStream(this, stream, options); 146 } 147 IsAggregate()148 static constexpr bool IsAggregate() { return false; } 149 SizeInBits()150 static constexpr int SizeInBits() { return Parameters::kBits; } 151 152 private: 153 BitViewType buffer_; 154 }; 155 156 } // namespace support 157 } // namespace emboss 158 159 #endif // EMBOSS_RUNTIME_CPP_EMBOSS_ENUM_VIEW_H_ 160