Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper functions for conversions that are locale independent #233

Open
j-rivero opened this issue Jul 26, 2021 · 3 comments
Open

Helper functions for conversions that are locale independent #233

j-rivero opened this issue Jul 26, 2021 · 3 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@j-rivero
Copy link
Contributor

j-rivero commented Jul 26, 2021

Desired behavior

Different software in the Ignition family uses all kind of C/C++ functions to convert between types that are locale dependent and make functionality to fail under non C locales. Examples are:

Trying to complete the list (split due to limitations in github search) based on https://www.gnu.org/software/libc/manual/html_node/Parsing-of-Numbers.html:

Alternatives considered

There is a native function in C++17 https://en.cppreference.com/w/cpp/utility/to_chars which is not available in all supported platforms at this time. The boost::lexical_cast could be an option but would be ideal not to depend on boost if possible.

Implementation suggestion

I think that the best approach would be to implement helper functions that encapsulate the implementation in this ign-common repository. The implementation can rely on to_chars if C++17 is available or use other workarounds (see ros/urdfdom_headers#42).

A similar work was done for sdformat years ago. Following the locale_fix test can lead to details.

@peci1
Copy link
Contributor

peci1 commented May 24, 2022

I've found https://github.com/fastfloat/fast_float which provides MIT-licensed implementation of the floating-point variants of std::from_chars for compilers with only C++11 support.

From the benchmarks it has in the README, it seems it is the fastest available option.

@peci1
Copy link
Contributor

peci1 commented May 24, 2022

I wrote a shim for the functionality that should be working generally at least since GCC 7 (shimming the support via fast_float). I think something similar could be used here.

cmake/from_chars_try_compile.cpp:

#include <charconv>

void fn()
{
  double d;
  const char* s = "1.0";
  std::from_chars(s, s + 3, d);
}

CMakeLists.txt:

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
try_compile(HAS_FROM_CHARS_FLOAT
  ${CMAKE_BINARY_DIR}/from_chars ${CMAKE_CURRENT_SOURCE_DIR}/cmake/from_chars_try_compile.cpp
  CXX_STANDARD 17)
...
if (HAS_FROM_CHARS_FLOAT)
  target_compile_definitions(target PRIVATE HAS_FROM_CHARS_FLOAT=1)
endif()

from_chars.h:

#pragma once
#include <system_error>

namespace cras
{
  enum chars_format
  {
    scientific = 1 << 0,
    fixed = 1 << 2,
    hex = 1 << 3,
    general = fixed | scientific
  };
  
  struct from_chars_result
  {
    const char* ptr;
    ::std::errc ec;
  };

  ::cras::from_chars_result from_chars(const char* first, const char* last, float& value,
    ::cras::chars_format fmt = ::cras::chars_format::general) noexcept;

  ::cras::from_chars_result from_chars(const char* first, const char* last, double& value,
    ::cras::chars_format fmt = ::cras::chars_format::general) noexcept;
}

from_chars.cpp:

#include "from_chars.h"
#if defined(HAS_FROM_CHARS_FLOAT) && HAS_FROM_CHARS_FLOAT == 1

#include <charconv>

namespace cras
{

cras::from_chars_result from_chars(const char* first, const char* last, float& value,
                                   const cras::chars_format fmt) noexcept
{
  auto result = std::from_chars(first, last, value, static_cast<std::chars_format>(fmt));
  return {result.ptr, result.ec};
}

cras::from_chars_result from_chars(const char* first, const char* last, double& value,
                                   const cras::chars_format fmt) noexcept
{
  auto result = std::from_chars(first, last, value, static_cast<std::chars_format>(fmt));
  return {result.ptr, result.ec};
}

}

#else

#include <fast_float/fast_float.h>

namespace cras
{

cras::from_chars_result from_chars(const char* first, const char* last, float& value,
  const cras::chars_format fmt) noexcept
{
  auto result = fast_float::from_chars(first, last, value, static_cast<fast_float::chars_format>(fmt));
  return {result.ptr, result.ec};
}

cras::from_chars_result from_chars(const char* first, const char* last, double& value,
  const cras::chars_format fmt) noexcept
{
  auto result = fast_float::from_chars(first, last, value, static_cast<fast_float::chars_format>(fmt));
  return {result.ptr, result.ec};
}

}

#endif

@chapulina
Copy link
Contributor

Interesting, maybe we could vendor that on gz-utils to make it available to all libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants