muse-sequencer / muse

MusE is a digital audio workstation with support for both Audio and MIDI
https://muse-sequencer.github.io/
Other
634 stars 67 forks source link

Rewrite functions for using standard cpp libs #1122

Closed donarturo11 closed 1 year ago

donarturo11 commented 1 year ago

Goals

terminator356 commented 1 year ago

Hi! In the following test code which includes both the existing and proposed new function versions, unless I've entered something wrong, there is a problem, shown after this listing:

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <vector>
#include <locale>
#include <sstream>
#include <QString>

//===========================
// Existing functions:
//===========================

QString museStringFromDouble(double v)
{
  // NOTE: snprintf can be locale sensitive! We should force the locale to standard 'C'.
  // Use a per-thread thread-safe technique instead of setting the global locale.
  // Note this C locale is NOT the same as the application's C++ locale.
  // Setting LANG environment variable before running is different than setting our -l switch.
  locale_t nloc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
  assert(nloc != (locale_t) 0);
  uselocale(nloc);

  bool useh = false;
  int sz;
  // How many characters required in the decimal string?
  // Use a very large precision to get all the digits.
  sz = std::snprintf(nullptr, 0, "%.100g", v);
  // If the decimal size is 10 or less, use it.
  if(sz > 10)
  {
    // How many characters required in the hex string?
    const int hsz = std::snprintf(nullptr, 0, "%a", v);
    // If the hex size is less than the decimal size, use it.
    if(hsz < sz)
    {
      sz = hsz;
      useh = true;
    }
  }
  // Note +1 for null terminator since the returned size doesn't include it.
  std::vector<char> buf(sz + 1);
  if(useh)
    std::snprintf(&buf[0], buf.size(), "%a", v);
  else
    std::snprintf(&buf[0], buf.size(), "%.100g", v);

  // NOTE: LC_GLOBAL_HANDLE? Seems to be a mistake in the uselocale() documentation example.
  //uselocale(LC_GLOBAL_HANDLE);
  // So the new locale is no longer in use.
  uselocale(LC_GLOBAL_LOCALE);
  freelocale(nloc);

  return QString(&buf[0]);
}

double museStringToDouble(const QString &s, bool *ok)
{
  const char *sc = s.toLatin1().constData();
  char *end;

  // NOTE: strtod is locale sensitive! We must force the locale to standard 'C'.
  // Use a per-thread thread-safe technique instead of setting the global locale.
  // Note this C locale is NOT the same as the application's C++ locale.
  // Setting LANG environment variable before running is different than setting our -l switch.
  locale_t nloc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
  assert(nloc != (locale_t) 0);
  uselocale(nloc);

  const double rv = std::strtod(sc, &end);
  if(ok)
    // If the conversion fails, strtod sets end = input string.
    *ok = end != sc;

  // NOTE: LC_GLOBAL_HANDLE? Seems to be a mistake in the uselocale() documentation example.
  //uselocale(LC_GLOBAL_HANDLE);
  // So the new locale is no longer in use.
  uselocale(LC_GLOBAL_LOCALE);
  freelocale(nloc);

  return rv;
}

//===========================
// Proposed new functions:
//===========================

QString museStringFromDouble_2(double v)
{
  std::stringstream ss;
     ss.precision(100);
     ss.imbue(std::locale("C"));
     ss << v;
     if (ss.str().size() > 10)
     {
         ss.str("");
         ss << std::hexfloat << v;
     }

  return QString::fromLatin1(ss.str().c_str());
}

double museStringToDouble_2(const QString &s, bool *ok)
{
  return s.toDouble(ok);
}

//===========================
// Main function:
//===========================

int main(int argc, char *argv[])
{
    const double d1 = 0.1234;
    {
        QString d1_string = museStringFromDouble(d1);
        fprintf(stderr, "d1:%f d1_string:%s\n", d1, d1_string.toUtf8().constData());
        bool ok = false;
        const double d2 = museStringToDouble(d1_string, &ok);
        fprintf(stderr, "d2:%f ok:%d\n", d2, ok);
    }

    {
        QString d1_string_2 = museStringFromDouble_2(d1);
        fprintf(stderr, "d1:%f d1_string_2:%s\n", d1, d1_string_2.toUtf8().constData());
        bool ok = false;
        const double d2_2 = museStringToDouble_2(d1_string_2, &ok);
        fprintf(stderr, "d2_2:%f ok:%d\n", d2_2, ok);
    }

    return 0;
}

The above test produces the following output:

// Original functions:
d1:0.123400 d1_string:0x1.f972474538ef3p-4
d2:0.123400 ok:1

// Proposed new functions:
d1:0.123400 d1_string_2:0x1.f972474538ef3p-4
d2_2:0.000000 ok:0

I like the new museStringFromDouble(), it seems OK so far. But can you think of a way to make a better museStringToDouble()? It needs to be able to handle hex floats, as well as using only the c locale. (Only c locale is used because we avoid foreign number formats in song files, for maximum file portability.) I researched and found that Qt's own string functions do not seem to support hex floats at all. That is why museStringToDouble() was written that way. It may seem odd and out of place, but it works.

An important related note:

A few weeks ago, I switched our disk audio pre-fetch thread from real-time to normal priority. Real-time priority seemed unnecessary - hey, it's just a disk thread - so I lowered the priority. We were using linux pthreads to achieve real-time settings. And we are still using pthreads even though we don't need real-time any more.

So I made a note in the code and ChangeLog that this means we should be able to switch from using linux pthreads to using a simple QThread instead. That is an important step in porting to Mingw, because if I understand correctly, and as I warned you earlier, MusE cannot be built with Mingw if we are using linux pthreads. My understanding is that only CodeWeavers' Crossover products include pthreads support.

Note that we also use pthreads for our ALSA timer - however our ALSA support is disabled on Windows, and this means with the changes planned above, we could be completely free of any linux pthreads requirement when building for Windows :-)

I am still monitoring for feedback from users about whether the disk thread switch was a good move. So it may change back again if it becomes necessary. I hope it is not necessary.

donarturo11 commented 1 year ago

@terminator356 Thanks for test. Maybe now will be better. I can't only understand, why QString doesn't convert from string to double, while STL makes very well.

donarturo11 commented 1 year ago

@terminator356 A propos porting to windows. At this time, first to resolve are undefined symbols, so I'm searching external symbols to export. But I don't know yet if add __declspec should be dependent of operating system, by adding to global header:

#ifndef IMPORT
  #ifdef _WIN32
  #define IMPORT __declspec(dllimport)
  #else
  #define IMPORT
  #endif
#endif
#ifndef EXPORT
  #ifdef _WIN32
  #define EXPORT __declspec(dllexport)
  #else
  #define EXPORT
  #endif
#endif

I noticed too that add WIN32 definition near _WIN32 is necessary for liblo, where Windows includes are dependent of WIN32:

// lo_endian.h:23
#if defined(WIN32) || defined(_MSC_VER)
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netinet/in.h>
#endif
terminator356 commented 1 year ago
std::stringstream ss;
double value;
size_t end;
ss.imbue(std::locale("C"));
ss << s.toStdString();
value = std::stod(ss.str(), &end);
*ok = (s.size() == end);
return value;

Unfortunately, that does not work either. std::stod() uses c locale whereas imbue() sets the c++ locale on only the stream. So using imbue() has no effect on the locale that std::stod() uses. The c locale must be set before calling std::stod(), by calling newlocale() and uselocale() etc.

A solution that I found in the example at https://en.cppreference.com/w/cpp/io/manip/fixed is to use istringstream like this:

// Note; choose clang for correct output
    double f;
    std::istringstream("0x1.8p+0") >> f;
    std::cout << "Parsing 0x1.8p+0 gives " << f << '\n';

Unfortunately, as the example says, this only works with CLang - not GCC !!! Run the example using the 'run' button with clang vs. gcc and see for yourself. I have researched the problem and it is very ugly and messy. A fix has only just been applied recently in GCC 13.1

[Sigh...] This is very, very frustrating ! It means we are currently out of luck trying to use C++ streams to read hex-floats.

Therefore I must now ask: What problem are you having with locale_t and MinGW, in the original museStringToDouble() code? I searched for "locale_t + mingw" and apparently it should work, with recent mingw, if I understand correctly.

Unfortunately the only path forward here, seems to be to get the original museStringToDouble() code to work on your mingw system. Can you post compiler output and show me what's going on? Maybe we can fix that?

Thanks. Tim.

donarturo11 commented 1 year ago

MINGW compiler output

$ ninja
[7/891] Building CXX object libs/string/CMakeFiles/muse_string.dir/hex_float.cpp.obj
FAILED: libs/string/CMakeFiles/muse_string.dir/hex_float.cpp.obj
C:\msys64\ucrt64\bin\c++.exe -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_SVG_LIB -DQT_UITOOLS_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -Dmuse_string_EXPORTS -IC:/msys64/src/muse/build-orig/libs/strin
g -IC:/msys64/src/muse/src/libs/string -IC:/msys64/src/muse/src/. -IC:/msys64/src/muse/src -IC:/msys64/src/muse/src/libs/evdata -IC:/msys64/src/muse/src/libs/memory -IC:/msys64/src/muse/src/libs
/midi_controller -IC:/msys64/src/muse/src/libs/midnam -IC:/msys64/src/muse/src/libs/mpevent -IC:/msys64/src/muse/src/libs/plugin -IC:/msys64/src/muse/src/libs/sysex_helper -IC:/msys64/src/muse/s
rc/libs/time_stretch -IC:/msys64/src/muse/src/libs/wave -IC:/msys64/src/muse/src/libs/xml -IC:/msys64/src/muse/src/muse -IC:/msys64/src/muse/src/muse/function_dialogs -IC:/msys64/src/muse/src/mu
se/widgets -IC:/msys64/src/muse/src/muse/components -IC:/msys64/src/muse/src/muse/instruments -IC:/msys64/src/muse/build-orig -IC:/msys64/src/muse/build-orig/muse -IC:/msys64/src/muse/build-orig
/muse/function_dialogs -IC:/msys64/src/muse/build-orig/muse/widgets -IC:/msys64/src/muse/build-orig/muse/components -IC:/msys64/src/muse/build-orig/muse/instruments -IC:/msys64/src/muse/build-or
ig/muse/ctrl -IC:/msys64/src/muse/src/vestige -IC:/msys64/ucrt64/include/opus -IC:/msys64/ucrt64/include/rtaudio -IC:/msys64/ucrt64/include/lilv-0 -IC:/msys64/ucrt64/include/serd-0 -IC:/msys64/u
crt64/include/sord-0 -IC:/msys64/ucrt64/include/sratom-0 -IC:/msys64/src/muse/src/muse/lv2Support -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtWi
dgets -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtGui -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtCore -isystem E:/SDKs/Qt/5.15.2/mingw81_64/./mkspecs/win32-g++ -isystem E:/SDKs/Qt/5.15.
2/mingw81_64/include/QtANGLE -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtUiTools -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtXml -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtSvg -Werr
or=format-security -Wextra -Winvalid-pch -fexceptions -Wall -fPIC -O2 -g -DNDEBUG -O2 -g -DNDEBUG -fomit-frame-pointer -ffast-math -fno-finite-math-only -std=c++17 -MD -MT libs/string/CMakeFiles
/muse_string.dir/hex_float.cpp.obj -MF libs\string\CMakeFiles\muse_string.dir\hex_float.cpp.obj.d -o libs/string/CMakeFiles/muse_string.dir/hex_float.cpp.obj -c C:/msys64/src/muse/src/libs/strin
g/hex_float.cpp
C:/msys64/src/muse/src/libs/string/hex_float.cpp: In function 'QString MusELib::museStringFromDouble(double)':
C:/msys64/src/muse/src/libs/string/hex_float.cpp:41:3: error: 'locale_t' was not declared in this scope; did you mean '_locale_t'?
   41 |   locale_t nloc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
      |   ^~~~~~~~
      |   _locale_t
C:/msys64/src/muse/src/libs/string/hex_float.cpp:43:13: error: 'nloc' was not declared in this scope
   43 |   uselocale(nloc);
      |             ^~~~
C:/msys64/src/muse/src/libs/string/hex_float.cpp:43:3: error: 'uselocale' was not declared in this scope; did you mean 'setlocale'?
   43 |   uselocale(nloc);
      |   ^~~~~~~~~
      |   setlocale
C:/msys64/src/muse/src/libs/string/hex_float.cpp:72:13: error: 'LC_GLOBAL_LOCALE' was not declared in this scope
   72 |   uselocale(LC_GLOBAL_LOCALE);
      |             ^~~~~~~~~~~~~~~~
C:/msys64/src/muse/src/libs/string/hex_float.cpp:73:3: error: 'freelocale' was not declared in this scope; did you mean '_free_locale'?
   73 |   freelocale(nloc);
      |   ^~~~~~~~~~
      |   _free_locale
C:/msys64/src/muse/src/libs/string/hex_float.cpp: In function 'double MusELib::museStringToDouble(const QString&, bool*)':
C:/msys64/src/muse/src/libs/string/hex_float.cpp:87:3: error: 'locale_t' was not declared in this scope; did you mean '_locale_t'?
   87 |   locale_t nloc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
      |   ^~~~~~~~
      |   _locale_t
C:/msys64/src/muse/src/libs/string/hex_float.cpp:89:13: error: 'nloc' was not declared in this scope
   89 |   uselocale(nloc);
      |             ^~~~
C:/msys64/src/muse/src/libs/string/hex_float.cpp:89:3: error: 'uselocale' was not declared in this scope; did you mean 'setlocale'?
   89 |   uselocale(nloc);
      |   ^~~~~~~~~
      |   setlocale
C:/msys64/src/muse/src/libs/string/hex_float.cpp:99:13: error: 'LC_GLOBAL_LOCALE' was not declared in this scope
   99 |   uselocale(LC_GLOBAL_LOCALE);
      |             ^~~~~~~~~~~~~~~~
C:/msys64/src/muse/src/libs/string/hex_float.cpp:100:3: error: 'freelocale' was not declared in this scope; did you mean '_free_locale'?
  100 |   freelocale(nloc);
      |   ^~~~~~~~~~
      |   _free_locale
[9/891] Building CXX object libs/midnam/CMakeFiles/midnam_module.dir/midnam.cpp.obj
ninja: build stopped: subcommand failed.
terminator356 commented 1 year ago

Thanks very much for the output.

So, it seems newlocale(), uselocale(), LC_GLOBAL_LOCALE etc. are not well supported on other platforms. That is sad. We will not be able to use them on mingw.

Can you tell me, is your compiler system using CLang? Maybe it is hard to find out, but I would like to know. If it is not using CLang, would it be difficult for you to install CLang and use it?

Using CLang would would solve the problem. we can use that easy one-liner that I mentioned above: For example: std::istringstream("0x1.8p+0") >> f;

donarturo11 commented 1 year ago

I'm trying on clang64. Mingw clang64 has not jack package, which is required.

terminator356 commented 1 year ago

Hm, that's interesting. So clang is definitely available and is being used? That's good news! OK, I will try a few things and commit and see if they work for you... Should be soon... Maybe less than one hour... ?

donarturo11 commented 1 year ago

I propose to use jack as optional. At this moment jack is not necessary to run muse, that's not true? So in CMakeLists.txt jack does not must be as required, eg. dependant of -DENABLE_JACK=0.

terminator356 commented 1 year ago

Jack should be optional. Agreed 100%. Yes, we should do that. I have been thinking about doing that. I never got around to it. :-(

But, keep in mind that without Jack or ALSA enabled, there will be no midi in MusE. Currently on Windows, Jack is the only way for MusE to have midi.

MusE has an audio driver which can be selected: 'RTAudio' which can take care of Windows audio for us. :-) Therefore, I agree that MusE's Jack audio driver should optional. (Qt also has built-in audio driver classes. I have been studying them for use in MusE. Good for cross-platform.)

However, then we will need to use something else for midi. An obvious choice would be 'RTMidi'. That's OK. 'RTMidi' is a good compliment to 'RTAudio' and it should be in MusE anyway. ;-) (Unfortunately Qt does not seem to have any midi support that I can find.)

donarturo11 commented 1 year ago

Well... I made simple script finding jack without pkgconfig, to find installation eg. in Program Files. I tried to build, but I have the same result with locale_t

art@DESKTOP-38KR1EM CLANG64 /src/muse/build
$ ninja
[5/876] Building CXX object libs/string/CMakeFiles/muse_string.dir/hex_float.cpp.obj
FAILED: libs/string/CMakeFiles/muse_string.dir/hex_float.cpp.obj
C:\msys64\clang64\bin\c++.exe -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_SVG_LIB -DQT_UITOOLS_LIB
 -DQT_WIDGETS_LIB -DQT_XML_LIB -Dmuse_string_EXPORTS -IC:/msys64/src/muse/build/libs/string -IC:/msy
s64/src/muse/src/libs/string -IC:/msys64/src/muse/src/. -IC:/msys64/src/muse/src -IC:/msys64/src/mus
e/src/libs/evdata -IC:/msys64/src/muse/src/libs/memory -IC:/msys64/src/muse/src/libs/midi_controller
 -IC:/msys64/src/muse/src/libs/midnam -IC:/msys64/src/muse/src/libs/mpevent -IC:/msys64/src/muse/src
/libs/plugin -IC:/msys64/src/muse/src/libs/sysex_helper -IC:/msys64/src/muse/src/libs/time_stretch -
IC:/msys64/src/muse/src/libs/wave -IC:/msys64/src/muse/src/libs/xml -IC:/msys64/src/muse/src/muse -I
C:/msys64/src/muse/src/muse/function_dialogs -IC:/msys64/src/muse/src/muse/widgets -IC:/msys64/src/m
use/src/muse/components -IC:/msys64/src/muse/src/muse/instruments -IC:/msys64/src/muse/build -IC:/ms
ys64/src/muse/build/muse -IC:/msys64/src/muse/build/muse/function_dialogs -IC:/msys64/src/muse/build
/muse/widgets -IC:/msys64/src/muse/build/muse/components -IC:/msys64/src/muse/build/muse/instruments
 -IC:/msys64/src/muse/build/muse/ctrl -IC:/msys64/src/muse/src/vestige -IC:/msys64/clang64/include/o
pus -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtWi
dgets -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtGui -isystem E:/SDKs/Qt/5.15.2/mingw81_64/incl
ude/QtCore -isystem E:/SDKs/Qt/5.15.2/mingw81_64/./mkspecs/win32-g++ -isystem E:/SDKs/Qt/5.15.2/ming
w81_64/include/QtANGLE -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtUiTools -isystem E:/SDKs/Qt/5
.15.2/mingw81_64/include/QtXml -isystem E:/SDKs/Qt/5.15.2/mingw81_64/include/QtSvg -Werror=format-se
curity -Wextra -Winvalid-pch -fexceptions -Wall -fPIC -O2 -g -DNDEBUG -O2 -g -DNDEBUG -fomit-frame-p
ointer -ffast-math -fno-finite-math-only -std=c++17 -MD -MT libs/string/CMakeFiles/muse_string.dir/h
ex_float.cpp.obj -MF libs\string\CMakeFiles\muse_string.dir\hex_float.cpp.obj.d -o libs/string/CMake
Files/muse_string.dir/hex_float.cpp.obj -c C:/msys64/src/muse/src/libs/string/hex_float.cpp
C:/msys64/src/muse/src/libs/string/hex_float.cpp:43:3: error: use of undeclared identifier 'uselocal
e'
  uselocale(nloc);
  ^
C:/msys64/src/muse/src/libs/string/hex_float.cpp:72:13: error: use of undeclared identifier 'LC_GLOB
AL_LOCALE'
  uselocale(LC_GLOBAL_LOCALE);
            ^
C:/msys64/src/muse/src/libs/string/hex_float.cpp:89:3: error: use of undeclared identifier 'uselocal
e'
  uselocale(nloc);
  ^
C:/msys64/src/muse/src/libs/string/hex_float.cpp:99:13: error: use of undeclared identifier 'LC_GLOB
AL_LOCALE'
  uselocale(LC_GLOBAL_LOCALE);
            ^
4 errors generated.
[7/876] Building CXX object libs/midnam/CMakeFiles/midnam_module.dir/midnam.cpp.obj
In file included from C:/msys64/src/muse/src/libs/midnam/midnam.cpp:24:
In file included from C:/msys64/src/muse/src/libs/midnam/midnam.h:33:
C:/msys64/src/muse/src/libs/mpevent/mpevent.h:187:47: warning: instantiation of variable 'MusECore::
audioMPEventRTalloc<std::__tree_node<MusECore::MidiPlayEvent, void *>>::pool' required here, but no
definition is available [-Wundefined-var-template]
    void deallocate(pointer p, size_type n) { pool.free(p, n); }
                                              ^
C:/msys64/clang64/include/c++/v1/__memory/allocator_traits.h:288:13: note: in instantiation of membe
r function 'MusECore::audioMPEventRTalloc<std::__tree_node<MusECore::MidiPlayEvent, void *>>::deallo
cate' requested here
        __a.deallocate(__p, __n);
            ^
C:/msys64/clang64/include/c++/v1/__tree:1814:24: note: in instantiation of member function 'std::all
ocator_traits<MusECore::audioMPEventRTalloc<std::__tree_node<MusECore::MidiPlayEvent, void *>>>::dea
llocate' requested here
        __node_traits::deallocate(__na, __nd, 1);
                       ^
C:/msys64/clang64/include/c++/v1/__tree:1801:3: note: in instantiation of member function 'std::__tr
ee<MusECore::MidiPlayEvent, std::less<MusECore::MidiPlayEvent>, MusECore::audioMPEventRTalloc<MusECo
re::MidiPlayEvent>>::destroy' requested here
  destroy(__root());
  ^
C:/msys64/clang64/include/c++/v1/set:1098:5: note: in instantiation of member function 'std::__tree<
MusECore::MidiPlayEvent, std::less<MusECore::MidiPlayEvent>, MusECore::audioMPEventRTalloc<MusECore:
:MidiPlayEvent>>::~__tree' requested here
    multiset()
    ^
C:/msys64/src/muse/src/libs/mpevent/mpevent.h:244:7: note: in instantiation of member function 'std:
:multiset<MusECore::MidiPlayEvent, std::less<MusECore::MidiPlayEvent>, MusECore::audioMPEventRTalloc
<MusECore::MidiPlayEvent>>::multiset' requested here
class MPEventList : public MPEL {
      ^
C:/msys64/src/muse/src/libs/mpevent/mpevent.h:166:37: note: forward declaration of template entity i
s here
    static TypedMemoryPool<T, 2048> pool;
                                    ^
C:/msys64/src/muse/src/libs/mpevent/mpevent.h:187:47: note: add an explicit instantiation declaratio
n to suppress this warning if 'MusECore::audioMPEventRTalloc<std::__tree_node<MusECore::MidiPlayEven
t, void *>>::pool' is explicitly instantiated in another translation unit
    void deallocate(pointer p, size_type n) { pool.free(p, n); }
                                              ^
1 warning generated.
ninja: build stopped: subcommand failed.
donarturo11 commented 1 year ago

I noticed yet, that for some libraries like libsndfile pkgconfig is not now needed because of presence of cmake modules. Is any reason to use pkgconfig instead cmake modules? I already FindJack.cmake written and I can push it.

donarturo11 commented 1 year ago

The most step to make this project more portable is to minimalize typically UNIX solutions and replace with standard cpp or Qt libraries and pretty put macros to export symbols to dll.

terminator356 commented 1 year ago

I have merged the pull request so that we may have your new museStringFromDouble().

But the museStringToDouble() will of course require some work. Hang on... I am working on a fix for it... You may see some temporary code in place until a real fix is written...

Thank you. Good work.

terminator356 commented 12 months ago

Hi @donarturo11 Sorry for the delay. This was a very difficult fix. What a trip...

Fixes pushed to master now.

Look at the commit to see what was necessary. In the end, it was ... different. I left some comments in the code about how and why it was done this way.

It turns out that only experimental clang versions support C++ isstringstream hexfloat formatting !! And GCC C++ is still in the process of adding support. So it will be a while before that happens. So I had to do something different while we wait for GCC support to arrive.

Instead of attempting to change locale before calling std::strtod(), I did the opposite: I 'prepare' or 'tailor' the text to fit the current locale before calling std::strtod ! No calls to c locale functions were required at all. In the case of hexfloats, the formal definition of a hexfloat reveals that only one lousy character needs to change - the decimal point. Nothing else. So only one new call to QLocale::decimalPoint() was required for that, at program start in main.cpp

When GCC stream hexfloat support arrives, or if someone uses an experimental clang version with support, my code will automatically switch to proper isstringstream hexfloats. I used a custom cmake function during configuration, to detect that.

Let me know if any trouble. Good luck. Anxiously awaiting... Thanks.