// bslstl_charconv.h                                                  -*-C++-*-
#ifndef INCLUDED_BSLSTL_CHARCONV
#define INCLUDED_BSLSTL_CHARCONV

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide implementations for functions not in the system library.
//
//@CLASSES:
//
//@CANONICAL_HEADER: bsl_charconv.h
//
//@SEE_ALSO: bsl+bslhdrs
//
//@DESCRIPTION: This component is for internal use only.  Please include
// '<bsl_charconv.h>' instead.  This component provides implementations for
// standard algorithms that are not provided by the underlying standard library
// implementation.  For example, 'to_chars' is a C++17 algorithm, and it is
// provided here for code using C++03 - C++14 or for compilers that do not
// provide '<charconv>' in C++17.
//
// 'to_chars' is locale-independent, non-allocating, and non-throwing, and
// provides a safe and more performant alternative to 'snprintf' in contexts
// where complex formatting options or locale are not important.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Demonstrating Writing a number to a 'streambuf'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to write a function that writes an 'int' to a 'streambuf'.
// We can use 'bsl::to_chars' to write the 'int' to a buffer, then write the
// buffer to the 'streambuf'.
//
// First, we declare our function:
//..
//  void writeJsonScalar(std::streambuf *result, int value)
//      // Write the specified 'value', in decimal, to the specified 'result'.
//  {
//..
// Then, we declare a buffer long enough to store any 'int' value in decimal.
//..
//      char buffer[11];        // size large enough to write 'INT_MIN', the
//                              // worst-case value, in decimal.
//..
// Next, we declare a variable to store the return value:
//..
//      bsl::to_chars_result sts;
//..
// Then, we call the function:
//..
//      sts = bsl::to_chars(buffer, buffer + sizeof(buffer), value);
//..
// Next, we check that the buffer was long enough, which should always be the
// case:
//..
//      assert(bsl::ErrcEnum() == sts.ec);
//..
// Now, we check that 'sts.ptr' is in the range
// '[ buffer + 1, buffer + sizeof(buffer) ]', which will always be the case
// whether 'to_chars' succeeded or failed.
//..
//      assert(buffer  <  sts.ptr);
//      assert(sts.ptr <= buffer + sizeof(buffer));
//..
// Finally, we write our buffer to the 'streambuf':
//..
//      result->sputn(buffer, sts.ptr - buffer);
//  }
//..

#include <bslscm_version.h>

#include <bslstl_errc.h>

#include <bslalg_numericformatterutil.h>
#include <bslmf_assert.h>
#include <bslmf_isintegral.h>
#include <bslmf_issame.h>
#include <bslmf_removecv.h>
#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP17_INT_CHARCONV)

#include <charconv>

#endif

namespace BloombergLP {
namespace bslstl {

                            // ========================
                            // struct 'to_chars_result'
                            // ========================

struct to_chars_result {
    // This 'struct' represents the result of the 'to_chars' function.  On a
    // successful call to 'to_chars_result', 'ptr' is the one past the end
    // pointer of the sequence of characters written, and 'ec' is a default
    // constructed ErrcEnum.  On failure, 'ptr' is set to the end of the buffer
    // supplied to 'to_chars' and 'ec' is set to 'errc::value_to_large'.

    // PUBLIC DATA
    char          *ptr;
    bsl::ErrcEnum  ec;
};

// FREE OPERATORS
template <class INTEGRAL_TYPE>
to_chars_result
to_chars(char *first, char *last, INTEGRAL_TYPE value, int base = 10);
    // Write the specified 'value' into the character buffer starting a the
    // specified 'first' and ending at the specified 'last'.  Optionally
    // specify 'base', the base in which the number is to be written.  If
    // 'base' is not specified, decimal is used.  Return a 'to_chars_result'
    // 'struct' indicating success or failure, and the end of the written
    // result.  On success, the output string is to begin at 'first', the 'ptr'
    // field in the return value is to point at the end of the representation,
    // and the 'ec' field will be 0.  If the buffer specified by
    // '[ first .. last )' is not large enough for the result, return a
    // 'struct' with 'ptr' set to 'last' and 'ec' set to
    // 'errc::value_too_large'.  Insufficient room in the output buffer is the
    // only failure mode.  The behavior is undefined unless 'first < last' and
    // 'base' is in the range '[ 2 .. 36 ]'.

// ============================================================================
//                         INLINE FUNCTION DEFINITIONS
// ============================================================================

// FREE OPERATORS
template <class INTEGRAL_TYPE>
inline
to_chars_result
to_chars(char *first, char *last, INTEGRAL_TYPE value, int base)
{
    BSLS_ASSERT(2 <= base);
    BSLS_ASSERT(base <= 36);
    BSLS_ASSERT(first < last);

    typedef bslalg::NumericFormatterUtil Util;
    typedef bsls::Types::Uint64          Uint64;

    BSLMF_ASSERT(bsl::is_integral<INTEGRAL_TYPE>::value);
    BSLMF_ASSERT(!(bsl::is_same<typename bsl::remove_cv<INTEGRAL_TYPE>::type,
                                bool>::value));
    BSLMF_ASSERT(sizeof(INTEGRAL_TYPE) <= sizeof(Uint64));

    char *end = Util::toChars(first, last, value, base);
    if (!end) {
        const to_chars_result ret = { last, bsl::errc::value_too_large };
        return ret;                                                   // RETURN
    }

    const to_chars_result ret = { end , bsl::ErrcEnum() };
    return ret;
}

}  // close package namespace
}  // close enterprise namespace

namespace bsl {

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP17_INT_CHARCONV)

using std::to_chars_result;
using std::to_chars;
using std::from_chars;
using std::from_chars_result;

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP17_CHARCONV)
using std::chars_format;
#endif

#else

using BloombergLP::bslstl::to_chars_result;
using BloombergLP::bslstl::to_chars;

#endif

}  // close namespace bsl

#endif  // INCLUDED_BSLSTL_CHARCONV

// ----------------------------------------------------------------------------
// Copyright 2020 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------