1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 #ifndef T_CONST_VALUE_H 21 #define T_CONST_VALUE_H 22 23 #include "thrift/parse/t_enum.h" 24 #include <stdint.h> 25 #include <map> 26 #include <vector> 27 #include <string> 28 29 /** 30 * A const value is something parsed that could be a map, set, list, struct 31 * or whatever. 32 * 33 */ 34 class t_const_value { 35 public: 36 /** 37 * Comparator to sort fields in ascending order by key. 38 * Make this a functor instead of a function to help GCC inline it. 39 */ 40 struct value_compare { 41 public: operatorvalue_compare42 bool operator()(t_const_value const* const& left, t_const_value const* const& right) const { 43 return *left < *right; 44 } 45 }; 46 47 enum t_const_value_type { CV_INTEGER, CV_DOUBLE, CV_STRING, CV_MAP, CV_LIST, CV_IDENTIFIER, CV_UNKNOWN }; 48 t_const_value()49 t_const_value() : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) {} 50 t_const_value(int64_t val)51 t_const_value(int64_t val) : doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) { set_integer(val); } 52 t_const_value(std::string val)53 t_const_value(std::string val) : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) { set_string(val); } 54 set_string(std::string val)55 void set_string(std::string val) { 56 valType_ = CV_STRING; 57 stringVal_ = val; 58 } 59 get_string()60 std::string get_string() const { return stringVal_; } 61 set_integer(int64_t val)62 void set_integer(int64_t val) { 63 valType_ = CV_INTEGER; 64 intVal_ = val; 65 } 66 get_integer()67 int64_t get_integer() const { 68 if (valType_ == CV_IDENTIFIER) { 69 if (enum_ == nullptr) { 70 throw "have identifier \"" + get_identifier() + "\", but unset enum on line!"; 71 } 72 std::string identifier = get_identifier(); 73 std::string::size_type dot = identifier.rfind('.'); 74 if (dot != std::string::npos) { 75 identifier = identifier.substr(dot + 1); 76 } 77 t_enum_value* val = enum_->get_constant_by_name(identifier); 78 if (val == nullptr) { 79 throw "Unable to find enum value \"" + identifier + "\" in enum \"" + enum_->get_name() 80 + "\""; 81 } 82 return val->get_value(); 83 } else { 84 return intVal_; 85 } 86 } 87 set_uuid(std::string val)88 void set_uuid(std::string val) { 89 validate_uuid(val); 90 valType_ = CV_STRING; 91 stringVal_ = val; 92 } 93 get_uuid()94 std::string get_uuid() const { 95 std::string tmp = stringVal_; 96 validate_uuid(tmp); 97 return tmp; 98 } 99 set_double(double val)100 void set_double(double val) { 101 valType_ = CV_DOUBLE; 102 doubleVal_ = val; 103 } 104 get_double()105 double get_double() const { return doubleVal_; } 106 set_map()107 void set_map() { valType_ = CV_MAP; } 108 add_map(t_const_value * key,t_const_value * val)109 void add_map(t_const_value* key, t_const_value* val) { mapVal_[key] = val; } 110 get_map()111 const std::map<t_const_value*, t_const_value*, t_const_value::value_compare>& get_map() const { return mapVal_; } 112 set_list()113 void set_list() { valType_ = CV_LIST; } 114 add_list(t_const_value * val)115 void add_list(t_const_value* val) { listVal_.push_back(val); } 116 get_list()117 const std::vector<t_const_value*>& get_list() const { return listVal_; } 118 set_identifier(std::string val)119 void set_identifier(std::string val) { 120 valType_ = CV_IDENTIFIER; 121 identifierVal_ = val; 122 } 123 get_identifier()124 std::string get_identifier() const { return identifierVal_; } 125 get_identifier_name()126 std::string get_identifier_name() const { 127 std::string ret = get_identifier(); 128 size_t s = ret.find('.'); 129 if (s == std::string::npos) { 130 throw "error: identifier " + ret + " is unqualified!"; 131 } 132 ret = ret.substr(s + 1); 133 s = ret.find('.'); 134 if (s != std::string::npos) { 135 ret = ret.substr(s + 1); 136 } 137 return ret; 138 } 139 get_identifier_with_parent()140 std::string get_identifier_with_parent() const { 141 std::string ret = get_identifier(); 142 size_t s = ret.find('.'); 143 if (s == std::string::npos) { 144 throw "error: identifier " + ret + " is unqualified!"; 145 } 146 size_t s2 = ret.find('.', s + 1); 147 if (s2 != std::string::npos) { 148 ret = ret.substr(s + 1); 149 } 150 return ret; 151 } 152 set_enum(t_enum * tenum)153 void set_enum(t_enum* tenum) { enum_ = tenum; } 154 get_type()155 t_const_value_type get_type() const { if (valType_ == CV_UNKNOWN) { throw std::string("unknown t_const_value"); } return valType_; } 156 157 /** 158 * Comparator to sort map fields in ascending order by key and then value. 159 * This is used for map comparison in lexicographic order. 160 */ 161 struct map_entry_compare { 162 private: 163 typedef std::pair<t_const_value*, t_const_value*> ConstPair; 164 public: operatormap_entry_compare165 bool operator()(ConstPair left, ConstPair right) const { 166 if (*(left.first) < *(right.first)) { 167 return true; 168 } else { 169 if (*(right.first) < *(left.first)) { 170 return false; 171 } else { 172 return *(left.second) < *(right.second); 173 } 174 } 175 } 176 }; 177 178 bool operator < (const t_const_value& that) const { 179 ::t_const_value::t_const_value_type t1 = get_type(); 180 ::t_const_value::t_const_value_type t2 = that.get_type(); 181 if (t1 != t2) 182 return t1 < t2; 183 switch (t1) { 184 case ::t_const_value::CV_INTEGER: 185 return intVal_ < that.intVal_; 186 case ::t_const_value::CV_DOUBLE: 187 return doubleVal_ < that.doubleVal_; 188 case ::t_const_value::CV_STRING: 189 return stringVal_ < that.stringVal_; 190 case ::t_const_value::CV_IDENTIFIER: 191 return identifierVal_ < that.identifierVal_; 192 case ::t_const_value::CV_MAP: 193 return std::lexicographical_compare( 194 mapVal_.begin(), mapVal_.end(), that.mapVal_.begin(), that.mapVal_.end(), map_entry_compare()); 195 case ::t_const_value::CV_LIST: 196 return std::lexicographical_compare( 197 listVal_.begin(), listVal_.end(), that.listVal_.begin(), that.listVal_.end(), value_compare()); 198 case ::t_const_value::CV_UNKNOWN: 199 default: 200 throw "unknown value type"; 201 } 202 } 203 204 private: 205 std::map<t_const_value*, t_const_value*, value_compare> mapVal_; 206 std::vector<t_const_value*> listVal_; 207 std::string stringVal_; 208 int64_t intVal_; 209 double doubleVal_; 210 std::string identifierVal_; 211 t_enum* enum_; 212 213 t_const_value_type valType_; 214 validate_uuid(std::string & uuid)215 void validate_uuid(std::string & uuid) const { 216 const std::string HEXCHARS = std::string("0123456789ABCDEFabcdef"); 217 218 // we also allow for usual "Windows GUID" format "{01234567-9012-4567-9012-456789012345}" 219 if ((uuid.length() == 38) && ('{' == uuid[0]) && ('}' == uuid[37])) { 220 uuid = uuid.substr(1, 36); 221 } 222 223 // canonical format "01234567-9012-4567-9012-456789012345" expected 224 bool valid = (uuid.length() == 36); 225 for (size_t i = 0; valid && (i < uuid.length()); ++i) { 226 switch(i) { 227 case 8: 228 case 13: 229 case 18: 230 case 23: 231 if(uuid[i] != '-') { 232 valid = false; 233 } 234 break; 235 default: 236 if(HEXCHARS.find(uuid[i]) == std::string::npos) { 237 valid = false; 238 } 239 break; 240 } 241 } 242 243 if( ! valid) { 244 throw "invalid uuid " + uuid; 245 } 246 } 247 }; 248 249 #endif 250