1 1.1 jmmv // Copyright 2012 Google Inc. 2 1.1 jmmv // All rights reserved. 3 1.1 jmmv // 4 1.1 jmmv // Redistribution and use in source and binary forms, with or without 5 1.1 jmmv // modification, are permitted provided that the following conditions are 6 1.1 jmmv // met: 7 1.1 jmmv // 8 1.1 jmmv // * Redistributions of source code must retain the above copyright 9 1.1 jmmv // notice, this list of conditions and the following disclaimer. 10 1.1 jmmv // * Redistributions in binary form must reproduce the above copyright 11 1.1 jmmv // notice, this list of conditions and the following disclaimer in the 12 1.1 jmmv // documentation and/or other materials provided with the distribution. 13 1.1 jmmv // * Neither the name of Google Inc. nor the names of its contributors 14 1.1 jmmv // may be used to endorse or promote products derived from this software 15 1.1 jmmv // without specific prior written permission. 16 1.1 jmmv // 17 1.1 jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 1.1 jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 1.1 jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 1.1 jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 1.1 jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 jmmv 29 1.1 jmmv #include "utils/units.hpp" 30 1.1 jmmv 31 1.1 jmmv extern "C" { 32 1.1 jmmv #include <stdint.h> 33 1.1 jmmv } 34 1.1 jmmv 35 1.1 jmmv #include <stdexcept> 36 1.1 jmmv 37 1.1 jmmv #include "utils/format/macros.hpp" 38 1.1 jmmv #include "utils/text/exceptions.hpp" 39 1.1 jmmv #include "utils/text/operations.ipp" 40 1.1 jmmv 41 1.1 jmmv namespace units = utils::units; 42 1.1 jmmv 43 1.1 jmmv 44 1.1 jmmv /// Constructs a zero bytes quantity. 45 1.1 jmmv units::bytes::bytes(void) : 46 1.1 jmmv _count(0) 47 1.1 jmmv { 48 1.1 jmmv } 49 1.1 jmmv 50 1.1 jmmv 51 1.1 jmmv /// Constructs an arbitrary bytes quantity. 52 1.1 jmmv /// 53 1.1 jmmv /// \param count_ The amount of bytes in the quantity. 54 1.1 jmmv units::bytes::bytes(const uint64_t count_) : 55 1.1 jmmv _count(count_) 56 1.1 jmmv { 57 1.1 jmmv } 58 1.1 jmmv 59 1.1 jmmv 60 1.1 jmmv /// Parses a string into a bytes quantity. 61 1.1 jmmv /// 62 1.1 jmmv /// \param in_str The user-provided string to be converted. 63 1.1 jmmv /// 64 1.1 jmmv /// \return The converted bytes quantity. 65 1.1 jmmv /// 66 1.1 jmmv /// \throw std::runtime_error If the input string is empty or invalid. 67 1.1 jmmv units::bytes 68 1.1 jmmv units::bytes::parse(const std::string& in_str) 69 1.1 jmmv { 70 1.1 jmmv if (in_str.empty()) 71 1.1 jmmv throw std::runtime_error("Bytes quantity cannot be empty"); 72 1.1 jmmv 73 1.1 jmmv uint64_t multiplier; 74 1.1 jmmv std::string str = in_str; 75 1.1 jmmv { 76 1.1 jmmv const char unit = str[str.length() - 1]; 77 1.1 jmmv switch (unit) { 78 1.1 jmmv case 'T': case 't': multiplier = TB; break; 79 1.1 jmmv case 'G': case 'g': multiplier = GB; break; 80 1.1 jmmv case 'M': case 'm': multiplier = MB; break; 81 1.1 jmmv case 'K': case 'k': multiplier = KB; break; 82 1.1 jmmv default: multiplier = 1; 83 1.1 jmmv } 84 1.1 jmmv if (multiplier != 1) 85 1.1 jmmv str.erase(str.length() - 1); 86 1.1 jmmv } 87 1.1 jmmv 88 1.1 jmmv if (str.empty()) 89 1.1 jmmv throw std::runtime_error("Bytes quantity cannot be empty"); 90 1.1 jmmv if (str[0] == '.' || str[str.length() - 1] == '.') { 91 1.1 jmmv // The standard parser for float values accepts things like ".3" and 92 1.1 jmmv // "3.", which means that we would interpret ".3K" and "3.K" as valid 93 1.1 jmmv // quantities. I think this is ugly and should not be allowed, so 94 1.1 jmmv // special-case this condition and just error out. 95 1.1 jmmv throw std::runtime_error(F("Invalid bytes quantity '%s'") % in_str); 96 1.1 jmmv } 97 1.1 jmmv 98 1.1 jmmv double count; 99 1.1 jmmv try { 100 1.1 jmmv count = text::to_type< double >(str); 101 1.1 jmmv } catch (const text::value_error& e) { 102 1.1 jmmv throw std::runtime_error(F("Invalid bytes quantity '%s'") % in_str); 103 1.1 jmmv } 104 1.1 jmmv 105 1.1 jmmv return bytes(uint64_t(count * multiplier)); 106 1.1 jmmv } 107 1.1 jmmv 108 1.1 jmmv 109 1.1 jmmv /// Formats a bytes quantity for user consumption. 110 1.1 jmmv /// 111 1.1 jmmv /// \return A textual representation of the bytes quantiy. 112 1.1 jmmv std::string 113 1.1 jmmv units::bytes::format(void) const 114 1.1 jmmv { 115 1.1 jmmv if (_count >= TB) { 116 1.1 jmmv return F("%.2sT") % (static_cast< float >(_count) / TB); 117 1.1 jmmv } else if (_count >= GB) { 118 1.1 jmmv return F("%.2sG") % (static_cast< float >(_count) / GB); 119 1.1 jmmv } else if (_count >= MB) { 120 1.1 jmmv return F("%.2sM") % (static_cast< float >(_count) / MB); 121 1.1 jmmv } else if (_count >= KB) { 122 1.1 jmmv return F("%.2sK") % (static_cast< float >(_count) / KB); 123 1.1 jmmv } else { 124 1.1 jmmv return F("%s") % _count; 125 1.1 jmmv } 126 1.1 jmmv } 127 1.1 jmmv 128 1.1 jmmv 129 1.1 jmmv /// Implicit conversion to an integral representation. 130 1.1 jmmv units::bytes::operator uint64_t(void) const 131 1.1 jmmv { 132 1.1 jmmv return _count; 133 1.1 jmmv } 134 1.1 jmmv 135 1.1 jmmv 136 1.1 jmmv /// Extracts a bytes quantity from a stream. 137 1.1 jmmv /// 138 1.1 jmmv /// \param input The stream from which to read a single word representing the 139 1.1 jmmv /// bytes quantity. 140 1.1 jmmv /// \param rhs The variable into which to store the parsed value. 141 1.1 jmmv /// 142 1.1 jmmv /// \return The input stream. 143 1.1 jmmv /// 144 1.1 jmmv /// \post The bad bit of input is set to 1 if the parsing failed. 145 1.1 jmmv std::istream& 146 1.1.1.2 jmmv units::operator>>(std::istream& input, bytes& rhs) 147 1.1 jmmv { 148 1.1 jmmv std::string word; 149 1.1 jmmv input >> word; 150 1.1 jmmv if (input.good() || input.eof()) { 151 1.1 jmmv try { 152 1.1.1.2 jmmv rhs = bytes::parse(word); 153 1.1 jmmv } catch (const std::runtime_error& e) { 154 1.1 jmmv input.setstate(std::ios::badbit); 155 1.1 jmmv } 156 1.1 jmmv } 157 1.1 jmmv return input; 158 1.1 jmmv } 159 1.1 jmmv 160 1.1 jmmv 161 1.1 jmmv /// Injects a bytes quantity into a stream. 162 1.1 jmmv /// 163 1.1 jmmv /// \param output The stream into which to inject the bytes quantity as a 164 1.1 jmmv /// user-readable string. 165 1.1 jmmv /// \param rhs The bytes quantity to format. 166 1.1 jmmv /// 167 1.1 jmmv /// \return The output stream. 168 1.1 jmmv std::ostream& 169 1.1.1.2 jmmv units::operator<<(std::ostream& output, const bytes& rhs) 170 1.1 jmmv { 171 1.1 jmmv return (output << rhs.format()); 172 1.1 jmmv } 173