1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <iterator>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 class Size {
25  public:
Size()26   Size() {}
27 
Size(int bits)28   Size(int bits) {
29     is_valid_ = true;
30     bits_ = bits;
31   }
32 
Size(std::string dynamic)33   Size(std::string dynamic) {
34     is_valid_ = true;
35     dynamic_.push_back(dynamic);
36   }
37 
Size(int bits,std::string dynamic)38   Size(int bits, std::string dynamic) {
39     is_valid_ = true;
40     bits_ = bits;
41     dynamic_.push_back(dynamic);
42   }
43 
Size(const Size & size)44   Size(const Size& size) {
45     is_valid_ = size.is_valid_;
46     bits_ = size.bits_;
47     dynamic_ = size.dynamic_;
48   }
49 
dynamic_string()50   std::string dynamic_string() const {
51     if (dynamic_.empty()) return "0";
52 
53     std::stringstream result;
54     // Print everything but the last element then append it manually to avoid
55     // the trailing "+" operator.
56     std::copy(dynamic_.begin(), dynamic_.end() - 1, std::ostream_iterator<std::string>(result, " + "));
57     result << dynamic_.back();
58     return result.str();
59   }
60 
dynamic_string_list()61   std::vector<std::string> dynamic_string_list() {
62     return dynamic_;
63   }
64 
empty()65   bool empty() const {
66     return !is_valid_;
67   }
68 
has_bits()69   bool has_bits() const {
70     return bits_ != 0;
71   }
72 
has_dynamic()73   bool has_dynamic() const {
74     return !dynamic_.empty();
75   }
76 
bits()77   int bits() const {
78     return bits_;
79   }
80 
bytes()81   int bytes() const {
82     // Round up to the nearest byte
83     return (bits_ + 7) / 8;
84   }
85 
86   Size operator+(int rhs) {
87     return Size(bits_ + rhs);
88   }
89 
90   Size operator+(std::string rhs) {
91     auto ret = Size();
92     ret.is_valid_ = true;
93     ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
94     ret.dynamic_.push_back(rhs);
95     return ret;
96   }
97 
98   Size operator+(const Size& rhs) {
99     auto ret = Size(bits_ + rhs.bits_);
100     ret.is_valid_ = is_valid_ && rhs.is_valid_;
101     ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
102     ret.dynamic_.insert(ret.dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
103     return ret;
104   }
105 
106   Size& operator+=(int rhs) {
107     is_valid_ = true;
108     bits_ += rhs;
109     return *this;
110   }
111 
112   Size& operator+=(std::string rhs) {
113     is_valid_ = true;
114     dynamic_.push_back(rhs);
115     return *this;
116   }
117 
118   Size& operator+=(const Size& rhs) {
119     is_valid_ = is_valid_ && rhs.is_valid_;
120     bits_ += rhs.bits_;
121     dynamic_.insert(dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
122     return *this;
123   }
124 
ToString()125   std::string ToString() const {
126     std::stringstream str;
127     str << "/* Bits: */ " << bits_ << " + /* Dynamic: */ " << dynamic_string();
128     if (!is_valid_) {
129       str << " (invalid) ";
130     }
131     return str.str();
132   }
133 
134   friend std::ostream& operator<<(std::ostream& os, const Size& rhs) {
135     return os << rhs.ToString();
136   }
137 
138  private:
139   bool is_valid_ = false;
140   int bits_ = 0;
141   std::vector<std::string> dynamic_;
142 };
143