Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-13 09:54:58

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_DT_TO_STRING_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_DT_TO_STRING_HPP
0010 
0011 #include <boost/mysql/time.hpp>
0012 
0013 #include <boost/assert.hpp>
0014 #include <boost/charconv/to_chars.hpp>
0015 #include <boost/core/span.hpp>
0016 
0017 #include <cstddef>
0018 #include <cstdint>
0019 #include <cstdlib>
0020 #include <system_error>
0021 #include <type_traits>
0022 
0023 // gcc-11+ issues spurious warnings about to_chars
0024 #if BOOST_GCC >= 70000
0025 #pragma GCC diagnostic push
0026 #pragma GCC diagnostic ignored "-Wstringop-overflow"
0027 #endif
0028 
0029 namespace boost {
0030 namespace mysql {
0031 namespace detail {
0032 
0033 // Helpers
0034 template <class IntType>
0035 inline char* call_to_chars(char* begin, char* end, IntType value) noexcept
0036 {
0037     auto r = charconv::to_chars(begin, end, value);
0038     BOOST_ASSERT(r.ec == std::errc());
0039     return r.ptr;
0040 }
0041 
0042 template <class UnsignedInt>
0043 inline char* write_pad2(char* begin, char* end, UnsignedInt value) noexcept
0044 {
0045     static_assert(std::is_unsigned<UnsignedInt>::value, "");
0046     if (value < 10u)
0047         *begin++ = '0';
0048     return call_to_chars(begin, end, value);
0049 }
0050 
0051 inline char* write_pad4(char* begin, char* end, unsigned long value) noexcept
0052 {
0053     for (auto l : {1000u, 100u, 10u})
0054     {
0055         if (value < l)
0056             *begin++ = '0';
0057     }
0058     return call_to_chars(begin, end, value);
0059 }
0060 
0061 inline char* write_pad6(char* begin, char* end, unsigned long value) noexcept
0062 {
0063     for (auto l : {100000u, 10000u, 1000u, 100u, 10u})
0064     {
0065         if (value < l)
0066             *begin++ = '0';
0067     }
0068     return call_to_chars(begin, end, value);
0069 }
0070 
0071 inline std::size_t date_to_string(
0072     std::uint16_t year,
0073     std::uint8_t month,
0074     std::uint8_t day,
0075     span<char, 32> output
0076 ) noexcept
0077 {
0078     // Worst-case output is 14 chars, extra space just in case
0079 
0080     // Iterators
0081     char* it = output.data();
0082     char* end = it + output.size();
0083 
0084     // Year
0085     it = write_pad4(it, end, year);
0086 
0087     // Month
0088     *it++ = '-';
0089     it = write_pad2(it, end, static_cast<unsigned long>(month));
0090 
0091     // Day
0092     *it++ = '-';
0093     it = write_pad2(it, end, static_cast<unsigned long>(day));
0094 
0095     // Done
0096     return it - output.data();
0097 }
0098 
0099 inline std::size_t datetime_to_string(
0100     std::uint16_t year,
0101     std::uint8_t month,
0102     std::uint8_t day,
0103     std::uint8_t hour,
0104     std::uint8_t minute,
0105     std::uint8_t second,
0106     std::uint32_t microsecond,
0107     span<char, 64> output
0108 ) noexcept
0109 {
0110     // Worst-case output is 37 chars, extra space just in case
0111 
0112     // Iterators
0113     char* it = output.data();
0114     char* end = it + output.size();
0115 
0116     // Date
0117     it += date_to_string(year, month, day, span<char, 32>(it, 32));
0118 
0119     // Hour
0120     *it++ = ' ';
0121     it = write_pad2(it, end, static_cast<unsigned long>(hour));
0122 
0123     // Minutes
0124     *it++ = ':';
0125     it = write_pad2(it, end, static_cast<unsigned long>(minute));
0126 
0127     // Seconds
0128     *it++ = ':';
0129     it = write_pad2(it, end, static_cast<unsigned long>(second));
0130 
0131     // Microseconds
0132     *it++ = '.';
0133     it = write_pad6(it, end, microsecond);
0134 
0135     // Done
0136     return it - output.data();
0137 }
0138 
0139 inline std::size_t time_to_string(::boost::mysql::time value, span<char, 64> output) noexcept
0140 {
0141     // Worst-case output is 34 chars, extra space just in case
0142 
0143     // Values. Note that std::abs(time::min()) invokes UB because of
0144     // signed integer overflow
0145     constexpr auto min_val = (::boost::mysql::time::min)();
0146     using unsigned_t = typename std::make_unsigned<typename ::boost::mysql::time::rep>::type;
0147     auto total_count = value == min_val ? static_cast<unsigned_t>(min_val.count())
0148                                         : static_cast<unsigned_t>(std::abs(value.count()));
0149 
0150     auto num_micros = total_count % 1000000u;
0151     total_count /= 1000000u;
0152 
0153     auto num_secs = total_count % 60u;
0154     total_count /= 60u;
0155 
0156     auto num_mins = total_count % 60u;
0157     total_count /= 60u;
0158 
0159     auto num_hours = total_count;
0160 
0161     // Iterators
0162     char* it = output.data();
0163     char* end = it + output.size();
0164 
0165     // Sign
0166     if (value.count() < 0)
0167         *it++ = '-';
0168 
0169     // Hours
0170     it = write_pad2(it, end, num_hours);  // type is unspecified
0171 
0172     // Minutes
0173     *it++ = ':';
0174     it = write_pad2(it, end, static_cast<unsigned long>(num_mins));
0175 
0176     // Seconds
0177     *it++ = ':';
0178     it = write_pad2(it, end, static_cast<unsigned long>(num_secs));
0179 
0180     // Microseconds
0181     *it++ = '.';
0182     it = write_pad6(it, end, static_cast<unsigned long>(num_micros));
0183 
0184     // Done
0185     return it - output.data();
0186 }
0187 
0188 }  // namespace detail
0189 }  // namespace mysql
0190 }  // namespace boost
0191 
0192 #if BOOST_GCC >= 110000
0193 #pragma GCC diagnostic pop
0194 #endif
0195 
0196 #endif