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()) {
52       return "0";
53     }
54 
55     std::stringstream result;
56     // Print everything but the last element then append it manually to avoid
57     // the trailing "+" operator.
58     std::copy(dynamic_.begin(), dynamic_.end() - 1,
59               std::ostream_iterator<std::string>(result, " + "));
60     result << dynamic_.back();
61     return result.str();
62   }
63 
dynamic_string_list()64   std::vector<std::string> dynamic_string_list() { return dynamic_; }
65 
empty()66   bool empty() const { return !is_valid_; }
67 
has_bits()68   bool has_bits() const { return bits_ != 0; }
69 
has_dynamic()70   bool has_dynamic() const { return !dynamic_.empty(); }
71 
bits()72   int bits() const { return bits_; }
73 
bytes()74   int bytes() const {
75     // Round up to the nearest byte
76     return (bits_ + 7) / 8;
77   }
78 
79   Size operator+(int rhs) { return Size(bits_ + rhs); }
80 
81   Size operator+(std::string rhs) {
82     auto ret = Size();
83     ret.is_valid_ = true;
84     ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
85     ret.dynamic_.push_back(rhs);
86     return ret;
87   }
88 
89   Size operator+(const Size& rhs) {
90     auto ret = Size(bits_ + rhs.bits_);
91     ret.is_valid_ = is_valid_ && rhs.is_valid_;
92     ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
93     ret.dynamic_.insert(ret.dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
94     return ret;
95   }
96 
97   Size& operator+=(int rhs) {
98     is_valid_ = true;
99     bits_ += rhs;
100     return *this;
101   }
102 
103   Size& operator+=(std::string rhs) {
104     is_valid_ = true;
105     dynamic_.push_back(rhs);
106     return *this;
107   }
108 
109   Size& operator+=(const Size& rhs) {
110     is_valid_ = is_valid_ && rhs.is_valid_;
111     bits_ += rhs.bits_;
112     dynamic_.insert(dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
113     return *this;
114   }
115 
ToString()116   std::string ToString() const {
117     std::stringstream str;
118     str << "/* Bits: */ " << bits_ << " + /* Dynamic: */ " << dynamic_string();
119     if (!is_valid_) {
120       str << " (invalid) ";
121     }
122     return str.str();
123   }
124 
125   friend std::ostream& operator<<(std::ostream& os, const Size& rhs) {
126     return os << rhs.ToString();
127   }
128 
129 private:
130   bool is_valid_ = false;
131   int bits_ = 0;
132   std::vector<std::string> dynamic_;
133 };
134