Альтернатива boost::lexical_cast
От: Feonyf  
Дата: 08.09.09 03:49
Оценка:
Пришел в голову способ как остаться при интерфейсе boost::lexical_cast но при этом сохранить скорость на уровне itoa atoi

1. А почему бустовцы так не сделали ?

2. Я что-то не понимаю ?

Приведённый ниже LexCast2 быстрее бустовского напорядок.

Полный пример с измерением быстродействия здесь http://files.rsdn.ru/46977/LexCast2.7z




tstring ConvertVar(int Src,boost::mpl::identity<tstring>)
{
  const int Size = 100;
  TCHAR dst[Size];
  const HRESULT hr = StringCchPrintf( dst, Size, _T("%d"), Src );
  if ( hr != S_OK ) {
    throw std::runtime_error("Integer can't be converted to string.");
  }
  return tstring(dst);
}

unsigned ConvertVar(int Src, boost::mpl::identity<unsigned>)
{
  if ( Src < 0 ) {
    throw std::runtime_error("Negative number."); 
  }
  return Src;
}

int ConvertVar(const tstring& Src,boost::mpl::identity<int>)
{
  int Result;
  if ( !StrToIntEx( Src.c_str(),STIF_SUPPORT_HEX,&Result) ) {
    throw std::runtime_error("String can't be converted to integer.");
  }
  return Result;
}

unsigned ConvertVar(const tstring& Src,boost::mpl::identity<unsigned>)
{
  const int tmp = ConvertVar(Src,boost::mpl::identity<int>());
  return ConvertVar(tmp, boost::mpl::identity<unsigned>());
}

template<class To,class From>
To LexCast2(From src)
{
  return ConvertVar(src,boost::mpl::identity<To>());
}

/*
Используется как boost::lexical_cast
*/
      const int Src = 6639;
      const tstring Dst(LexCast2<tstring>(Src));
Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re: Альтернатива boost::lexical_cast
От: jazzer Россия Skype: enerjazzer
Дата: 08.09.09 04:05
Оценка:
Здравствуйте, Feonyf, Вы писали:

F>Пришел в голову способ как остаться при интерфейсе boost::lexical_cast но при этом сохранить скорость на уровне itoa atoi


F>1. А почему бустовцы так не сделали ?


Потому что локали.
В твоем варианте, насколько я понимаю, их нет

Если локали не нужны, есть специальный макрос, типа BOOST_ASSUME_C_LOCALE (не помню точно), попробуй сравнить с ним
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Альтернатива boost::lexical_cast
От: Feonyf  
Дата: 08.09.09 05:17
Оценка:
Здравствуйте, jazzer, Вы писали:

J>В твоем варианте, насколько я понимаю, их нет


Нету. Но подумаю как сделать.

У lexical cast бустовского тоже нету локалей похоже
http://lists.boost.org/boost-users/2006/11/23444.php


> Is it possible to set a locale for the lexical_cast? It looks like that
> it is only possible to convert english/us numbers to a string?

No, it has been suggested several times and has always been rejected.

(The main reason seem to be that anything ending with _cast should only take a
single argument)

Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re[2]: Альтернатива boost::lexical_cast
От: Feonyf  
Дата: 08.09.09 05:26
Оценка:
Здравствуйте, jazzer, Вы писали:

J>(...)локали.

J>В твоем варианте, насколько я понимаю, их нет

Добавил это и появилась локаль


tstring ConvertVar(double Src,const char* Locale,boost::mpl::identity<tstring>)
{
  const int size = 100;
  TCHAR tmp[size];
  _locale_t locale = _create_locale(LC_ALL,Locale);
  if ( !locale ) {
    throw std::runtime_error("Invalid locale.");
  }
  const int result = _swprintf_s_l( tmp, size, _T("%e"), locale, Src );
  _free_locale(locale);
  if ( result == -1 ) {
    throw std::runtime_error("Double can't be converted to string.");
  }
  return tstring(tmp);
}

template<class To,class A1,class From>
To LexCast2(From src,A1 a1)
{
  return ConvertVar(src,a1,boost::mpl::identity<To>());
}

// использовать так (запятые отличаются):

      // English
      {
        const double Src = 12.78876;
        const tstring Dst(LexCast2<tstring>(Src,"English"));
        TEST_ASSERT( Dst == _T("1.278876e+001") );
      }
      // Russian
      {
        const double Src1 = 12.78876;
        const tstring Dst1(LexCast2<tstring>(Src1,"Russian"));
        TEST_ASSERT( Dst1 == _T("1,278876e+001") );
      }
Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re[3]: Альтернатива boost::lexical_cast
От: jazzer Россия Skype: enerjazzer
Дата: 08.09.09 05:38
Оценка:
Здравствуйте, Feonyf, Вы писали:

F>Здравствуйте, jazzer, Вы писали:


J>>В твоем варианте, насколько я понимаю, их нет


F>Нету. Но подумаю как сделать.


F>У lexical cast бустовского тоже нету локалей похоже

F>http://lists.boost.org/boost-users/2006/11/23444.php


F>

>> Is it possible to set a locale for the lexical_cast?


Локаль есть, та, что получили программа при старте, но ты не можешь ее изменить в рантайме на какую-то свою.

А то, о чем я говорю:
http://lists.boost.org/Archives/boost/2008/12/145737.php

> Someone was asking me today about the inefficiency of lexical_cast for
> its common itoa/atoi-like usage, and it occurred to me that it could
> *easily* be optimized to handle the common cases by dispatching to
> itoa/atoi ftoa/atof where available, and even sprintf. Seems like a
> great idea to me.

This can be easily done only if a program always uses the classic C and C++
locales. Optimization for some combinations of types is already available if
you set BOOST_LEXICAL_CAST_ASSUME_C_LOCALE.

Mapping between C and C++ locales is hard, if possible at all in a portable way.

Так что попробуй BOOST_LEXICAL_CAST_ASSUME_C_LOCALE и кинь результаты сравнения
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Альтернатива boost::lexical_cast
От: Feonyf  
Дата: 08.09.09 06:05
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Так что попробуй BOOST_LEXICAL_CAST_ASSUME_C_LOCALE и кинь результаты сравнения


Попробовал на бусте 1_40. Вставил в свой пример:

// stdafx.h : include file for standard system include files,
#pragma once

#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE


раскоментировал в своём примере:


#define LexCast2 boost::lexical_cast


однако boost::lexical_cast показал примерно такойже результат как без BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
Может что то я неправильно сделал ?
Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re[5]: Альтернатива boost::lexical_cast
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 08.09.09 11:50
Оценка:
Здравствуйте, Feonyf, Вы писали:
F>однако boost::lexical_cast показал примерно такойже результат как без BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
F>Может что то я неправильно сделал ?

Меня смущают непонятные вещи типа tstring. Я делал три уровня оптимизации, но все они предполагают, что типы Source и Target имеют известные типы. tstring в их число не входит.

Я не помню все детали, надо смотреть в коде, поэтому перечислю только главные идеи этих уровней

1. Source имеет тип, у которого известен максимальный размер текстового представления, но нет оптимизированной процедуры преобразования в Source в строку и нет оптимизированной процедуры преобразования из строки в Target. Например, мне лениво было разбираться с форматом IEEE для double. В таких случаях, вместо std::stringstring используется std::streambuf, указывающий на буфер на стеке.

2. Source имеет тип, который мы умеем преобразовать в строку _и_ Target имеет тип, который мы может преобразовать из строки. В таком случае ни std::stringstring ни std::streambuf не создается, а создается только объект std::locale.

3. Так же как пункт 2, но BOOST_LEXICAL_CAST_ASSUME_C_LOCALE позволяет избавится от создания объекта std::locale.

По этому поводу есть статья на сайте ACCU
http://accu.org/index.php/journals/1375
Re[6]: Альтернатива boost::lexical_cast
От: Feonyf  
Дата: 10.09.09 16:52
Оценка: :)
Здравствуйте, alnsn, Вы писали:

A>По этому поводу есть статья на сайте ACCU

A>http://accu.org/index.php/journals/1375

Наоптимизируют в обход stringstream для каждого типа. И потом зададут себе вопрос:
а зачем этот stringstream вообще нужен?

Нативный способ гораздо быстрее работает чем stringstream. Цифр приводить не буду, сами поиграетесь если нужно (тест выделять мне неохото).
Нативный способ:
void DoubleToTstringTest()
{
  double Src = 1.133;
  std::wstring Dst;
  VariantOwner vSrc,vDst;
  vSrc.v.vt = VT_R8;
  vSrc.v.dblVal = Src;
  const HRESULT hr = VariantChangeTypeEx(&vDst.v,&vSrc.v,g_lcidRU_RU,0,VT_BSTR);
  if ( hr != S_OK ) {
    throw std::runtime_error("Double can't be converted to string.");
  }
  Dst.assign(vDst.v.bstrVal,vDst.v.bstrVal+SysStringLen(vDst.v.bstrVal));
  //MessageBox(NULL,Dst.c_str(),L"Result",MB_OK);
}
Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re[3]: Альтернатива boost::lexical_cast
От: Roman Odaisky Украина  
Дата: 10.09.09 17:57
Оценка:
Здравствуйте, Feonyf, Вы писали:

F>Добавил это и появилась локаль

F>tstring ConvertVar(double Src,const char* Locale,boost::mpl::identity<tstring>)

А как же std::locale?
До последнего не верил в пирамиду Лебедева.
Re[7]: Альтернатива boost::lexical_cast
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 11.09.09 20:41
Оценка:
Здравствуйте, Feonyf, Вы писали:

F>Нативный способ:

F>
F>void DoubleToTstringTest()
F>{
F>  double Src = 1.133;
F>  std::wstring Dst;
F>  VariantOwner vSrc,vDst;
F>  vSrc.v.vt = VT_R8;
F>  vSrc.v.dblVal = Src;
F>  const HRESULT hr = VariantChangeTypeEx(&vDst.v,&vSrc.v,g_lcidRU_RU,0,VT_BSTR);
F>  if ( hr != S_OK ) {
F>    throw std::runtime_error("Double can't be converted to string.");
F>  }
F>  Dst.assign(vDst.v.bstrVal,vDst.v.bstrVal+SysStringLen(vDst.v.bstrVal));
F>  //MessageBox(NULL,Dst.c_str(),L"Result",MB_OK);
F>}
F>


Слов нет. Как все-таки хорошо, что у меня ни дома, ни на работе программированием для Windows не пахнет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.