1// File Description 2/// \file Tag.inl 3/// \brief Inline implementations for the Tag class. 4// 5// Author: Derek Barnett 6 7#include "pbbam/Tag.h" 8#include <boost/numeric/conversion/cast.hpp> 9#include <iostream> 10 11namespace PacBio { 12namespace BAM { 13namespace internal { 14 15template<typename T> 16inline bool InAsciiRange(const T x) 17{ return (x >=33 && x <= 127); } 18 19struct AsciiConvertVisitor : public boost::static_visitor<char> 20{ 21 // only valid for numeric types - maybe even more restrictive? 22 char operator() (const int8_t& x) const { return Helper(x); } 23 char operator() (const uint8_t& x) const { return Helper(x); } 24 char operator() (const int16_t& x) const { return Helper(x); } 25 char operator() (const uint16_t& x) const { return Helper(x); } 26 char operator() (const int32_t& x) const { return Helper(x); } 27 char operator() (const uint32_t& x) const { return Helper(x); } 28 29 // anything else always throws 30 template<typename T> 31 char operator()(const T&) const 32 { throw std::runtime_error{"conversion not supported"}; return 0; } 33 34private: 35 template<typename T> 36 char Helper(const T& x) const 37 { 38 if (!InAsciiRange(x)) 39 throw std::runtime_error{"not valid ASCII"}; 40 return static_cast<char>(x); 41 } 42}; 43 44template<typename DesiredType> 45struct NumericConvertVisitor : public boost::static_visitor<DesiredType> 46{ 47 // only valid for integral types 48 DesiredType operator() (const int8_t& x) const { return boost::numeric_cast<DesiredType>(x); } 49 DesiredType operator() (const uint8_t& x) const { return boost::numeric_cast<DesiredType>(x); } 50 DesiredType operator() (const int16_t& x) const { return boost::numeric_cast<DesiredType>(x); } 51 DesiredType operator() (const uint16_t& x) const { return boost::numeric_cast<DesiredType>(x); } 52 DesiredType operator() (const int32_t& x) const { return boost::numeric_cast<DesiredType>(x); } 53 DesiredType operator() (const uint32_t& x) const { return boost::numeric_cast<DesiredType>(x); } 54 55 // anything else always throws 56 template<typename T> DesiredType operator()(const T& t) const 57 { 58 const std::string from = typeid(t).name(); 59 const std::string to = typeid(DesiredType).name(); 60 const std::string msg = "conversion not supported: " + from + " -> " + to; 61 throw std::runtime_error(msg); 62 return 0; 63 } 64}; 65 66using ToInt8ConvertVisitor = NumericConvertVisitor<int8_t>; 67using ToUInt8ConvertVisitor = NumericConvertVisitor<uint8_t>; 68using ToInt16ConvertVisitor = NumericConvertVisitor<int16_t>; 69using ToUInt16ConvertVisitor = NumericConvertVisitor<uint16_t>; 70using ToInt32ConvertVisitor = NumericConvertVisitor<int32_t>; 71using ToUInt32ConvertVisitor = NumericConvertVisitor<uint32_t>; 72 73struct IsEqualVisitor : public boost::static_visitor<bool> 74{ 75 template <typename T, typename U> 76 bool operator() (const T&, const U&) const 77 { 78 // maybe allow conversions down the road? 79 // but for now, just fail if types are different 80 return false; 81 } 82 83 bool operator() (const boost::blank&, const boost::blank&) const 84 { return true; } 85 86 template <typename T> 87 bool operator() (const T& lhs, const T& rhs) const 88 { return lhs == rhs; } 89}; 90 91struct TypenameVisitor : public boost::static_visitor<std::string> 92{ 93 std::string operator() (const boost::blank&) const { return "none"; } 94 std::string operator() (const int8_t&) const { return "int8_t"; } 95 std::string operator() (const uint8_t&) const { return "uint8_t"; } 96 std::string operator() (const int16_t&) const { return "int16_t"; } 97 std::string operator() (const uint16_t&) const { return "uint16_t"; } 98 std::string operator() (const int32_t&) const { return "int32_t"; } 99 std::string operator() (const uint32_t&) const { return "uint32_t"; } 100 std::string operator() (const float&) const { return "float"; } 101 std::string operator() (const std::string&) const { return "string"; } 102 std::string operator() (const std::vector<int8_t>&) const { return "vector<int8_t>"; } 103 std::string operator() (const std::vector<uint8_t>&) const { return "vector<uint8_t>"; } 104 std::string operator() (const std::vector<int16_t>&) const { return "vector<int16_t>"; } 105 std::string operator() (const std::vector<uint16_t>&) const { return "vector<uint16_t>"; } 106 std::string operator() (const std::vector<int32_t>&) const { return "vector<int32_t>"; } 107 std::string operator() (const std::vector<uint32_t>&) const { return "vector<uint32_t>"; } 108 std::string operator() (const std::vector<float>&) const { return "vector<float>"; } 109}; 110 111} // namespace internal 112 113inline Tag::Tag(int8_t value) : data_{value} {} 114inline Tag::Tag(uint8_t value) : data_{value} {} 115inline Tag::Tag(int16_t value) : data_{value} {} 116inline Tag::Tag(uint16_t value) : data_{value} {} 117inline Tag::Tag(int32_t value) : data_{value} {} 118inline Tag::Tag(uint32_t value) : data_{value} {} 119inline Tag::Tag(float value) : data_{value} {} 120inline Tag::Tag(std::string value) : data_{std::move(value)} {} 121inline Tag::Tag(std::vector<int8_t> value) : data_{std::move(value)} {} 122inline Tag::Tag(std::vector<uint8_t> value) : data_{std::move(value)} {} 123inline Tag::Tag(std::vector<int16_t> value) : data_{std::move(value)} {} 124inline Tag::Tag(std::vector<uint16_t> value) : data_{std::move(value)} {} 125inline Tag::Tag(std::vector<int32_t> value) : data_{std::move(value)} {} 126inline Tag::Tag(std::vector<uint32_t> value) : data_{std::move(value)} {} 127inline Tag::Tag(std::vector<float> value) : data_{std::move(value)} {} 128 129inline Tag::Tag(int8_t value, const TagModifier mod) : data_{value}, modifier_(mod) 130{ 131 if (mod == TagModifier::HEX_STRING) 132 throw std::runtime_error{ 133 "HEX_STRING is not a valid tag modifier for int8_t data. " 134 "It is intended for string-type data only."}; 135} 136 137inline Tag::Tag(std::string value, TagModifier mod) : data_{std::move(value)}, modifier_{mod} 138{ 139 if (mod == TagModifier::ASCII_CHAR) 140 throw std::runtime_error{ 141 "ASCII_CHAR is not a valid tag modifier for string-type data. " 142 "To construct an ASCII char tag, use a single-quoted value (e.g. 'X' instead of " 143 "\"X\")"}; 144} 145 146inline Tag& Tag::operator=(boost::blank value) 147{ 148 data_ = value; 149 return *this; 150} 151 152inline Tag& Tag::operator=(int8_t value) 153{ 154 data_ = value; 155 return *this; 156} 157 158inline Tag& Tag::operator=(uint8_t value) 159{ 160 data_ = value; 161 return *this; 162} 163 164inline Tag& Tag::operator=(int16_t value) 165{ 166 data_ = value; 167 return *this; 168} 169 170inline Tag& Tag::operator=(uint16_t value) 171{ 172 data_ = value; 173 return *this; 174} 175 176inline Tag& Tag::operator=(int32_t value) 177{ 178 data_ = value; 179 return *this; 180} 181 182inline Tag& Tag::operator=(uint32_t value) 183{ 184 data_ = value; 185 return *this; 186} 187 188inline Tag& Tag::operator=(float value) 189{ 190 data_ = value; 191 return *this; 192} 193 194inline Tag& Tag::operator=(std::string value) 195{ 196 data_ = std::move(value); 197 return *this; 198} 199 200inline Tag& Tag::operator=(std::vector<int8_t> value) 201{ 202 data_ = std::move(value); 203 return *this; 204} 205 206inline Tag& Tag::operator=(std::vector<uint8_t> value) 207{ 208 data_ = std::move(value); 209 return *this; 210} 211 212inline Tag& Tag::operator=(std::vector<int16_t> value) 213{ 214 data_ = std::move(value); 215 return *this; 216} 217 218inline Tag& Tag::operator=(std::vector<uint16_t> value) 219{ 220 data_ = std::move(value); 221 return *this; 222} 223 224inline Tag& Tag::operator=(std::vector<int32_t> value) 225{ 226 data_ = std::move(value); 227 return *this; 228} 229 230inline Tag& Tag::operator=(std::vector<uint32_t> value) 231{ 232 data_ = std::move(value); 233 return *this; 234} 235 236inline Tag& Tag::operator=(std::vector<float> value) 237{ 238 data_ = std::move(value); 239 return *this; 240} 241 242inline bool Tag::operator== (const Tag& other) const 243{ 244 return boost::apply_visitor(internal::IsEqualVisitor(), data_, other.data_) && 245 (modifier_ == other.modifier_) ; 246} 247 248inline bool Tag::operator!= (const Tag& other) const 249{ return !(*this == other); } 250 251inline bool Tag::HasModifier(const TagModifier m) const 252{ 253 // we just allow one at a time (for now at least) 254 return modifier_ == m; 255} 256 257inline bool Tag::IsNull() const 258{ return Type() == TagDataType::INVALID; } 259 260inline bool Tag::IsInt8() const 261{ return Type() == TagDataType::INT8; } 262 263inline bool Tag::IsUInt8() const 264{ return Type() == TagDataType::UINT8; } 265 266inline bool Tag::IsInt16() const 267{ return Type() == TagDataType::INT16; } 268 269inline bool Tag::IsUInt16() const 270{ return Type() == TagDataType::UINT16; } 271 272inline bool Tag::IsInt32() const 273{ return Type() == TagDataType::INT32; } 274 275inline bool Tag::IsUInt32() const 276{ return Type() == TagDataType::UINT32; } 277 278inline bool Tag::IsFloat() const 279{ return Type() == TagDataType::FLOAT; } 280 281inline bool Tag::IsString() const 282{ return Type() == TagDataType::STRING; } 283 284inline bool Tag::IsHexString() const 285{ return IsString() && modifier_ == TagModifier::HEX_STRING; } 286 287inline bool Tag::IsInt8Array() const 288{ return Type() == TagDataType::INT8_ARRAY; } 289 290inline bool Tag::IsUInt8Array() const 291{ return Type() == TagDataType::UINT8_ARRAY; } 292 293inline bool Tag::IsInt16Array() const 294{ return Type() == TagDataType::INT16_ARRAY; } 295 296inline bool Tag::IsUInt16Array() const 297{ return Type() == TagDataType::UINT16_ARRAY; } 298 299inline bool Tag::IsInt32Array() const 300{ return Type() == TagDataType::INT32_ARRAY; } 301 302inline bool Tag::IsUInt32Array() const 303{ return Type() == TagDataType::UINT32_ARRAY; } 304 305inline bool Tag::IsFloatArray() const 306{ return Type() == TagDataType::FLOAT_ARRAY; } 307 308inline bool Tag::IsSignedInt() const 309{ return IsInt8() || IsInt16() || IsInt32(); } 310 311inline bool Tag::IsUnsignedInt() const 312{ return IsUInt8() || IsUInt16() || IsUInt32(); } 313 314inline bool Tag::IsIntegral() const 315{ return IsSignedInt() || IsUnsignedInt(); } 316 317inline bool Tag::IsNumeric() const 318{ return IsIntegral() || IsFloat(); } 319 320inline bool Tag::IsSignedArray() const 321{ return IsInt8Array() || IsInt16Array() || IsInt32Array(); } 322 323inline bool Tag::IsUnsignedArray() const 324{ return IsUInt8Array() || IsUInt16Array() || IsUInt32Array(); } 325 326inline bool Tag::IsIntegralArray() const 327{ return IsSignedArray() || IsUnsignedArray(); } 328 329inline bool Tag::IsArray() const 330{ return IsIntegralArray() || IsFloatArray(); } 331 332inline TagModifier Tag::Modifier() const 333{ return modifier_; } 334 335inline Tag& Tag::Modifier(const TagModifier m) 336{ modifier_ = m; return *this; } 337 338inline char Tag::ToAscii() const 339{ return boost::apply_visitor(internal::AsciiConvertVisitor(), data_); } 340 341inline int8_t Tag::ToInt8() const 342{ 343 if (IsInt8()) 344 return boost::get<int8_t>(data_); 345 return boost::apply_visitor(internal::ToInt8ConvertVisitor(), data_); 346} 347 348inline uint8_t Tag::ToUInt8() const 349{ 350 if (IsUInt8()) 351 return boost::get<uint8_t>(data_); 352 return boost::apply_visitor(internal::ToUInt8ConvertVisitor(), data_); 353} 354 355inline int16_t Tag::ToInt16() const 356{ 357 if (IsInt16()) 358 return boost::get<int16_t>(data_); 359 return boost::apply_visitor(internal::ToInt16ConvertVisitor(), data_); 360} 361 362inline uint16_t Tag::ToUInt16() const 363{ 364 if (IsUInt16()) 365 return boost::get<uint16_t>(data_); 366 return boost::apply_visitor(internal::ToUInt16ConvertVisitor(), data_); 367} 368 369inline int32_t Tag::ToInt32() const 370{ 371 if (IsInt32()) 372 return boost::get<int32_t>(data_); 373 return boost::apply_visitor(internal::ToInt32ConvertVisitor(), data_); 374} 375 376inline uint32_t Tag::ToUInt32() const 377{ 378 if (IsUInt32()) 379 return boost::get<uint32_t>(data_); 380 return boost::apply_visitor(internal::ToUInt32ConvertVisitor(), data_); 381} 382 383inline float Tag::ToFloat() const 384{ return boost::get<float>(data_); } 385 386inline std::string Tag::ToString() const 387{ return boost::get<std::string>(data_); } 388 389inline std::vector<int8_t> Tag::ToInt8Array() const 390{ return boost::get< std::vector<int8_t> >(data_); } 391 392inline std::vector<uint8_t> Tag::ToUInt8Array() const 393{ return boost::get< std::vector<uint8_t> >(data_); } 394 395inline std::vector<int16_t> Tag::ToInt16Array() const 396{ return boost::get< std::vector<int16_t> >(data_); } 397 398inline std::vector<uint16_t> Tag::ToUInt16Array() const 399{ return boost::get< std::vector<uint16_t> >(data_); } 400 401inline std::vector<int32_t> Tag::ToInt32Array() const 402{ return boost::get< std::vector<int32_t> >(data_); } 403 404inline std::vector<uint32_t> Tag::ToUInt32Array() const 405{ return boost::get< std::vector<uint32_t> >(data_); } 406 407inline std::vector<float> Tag::ToFloatArray() const 408{ return boost::get< std::vector<float> >(data_); } 409 410inline TagDataType Tag::Type() const 411{ return TagDataType(data_.which() ); } 412 413inline std::string Tag::Typename() const 414{ return boost::apply_visitor(internal::TypenameVisitor(), data_); } 415 416} // namespace BAM 417} // namespace PacBio 418