• C++字符串格式化库:CPPFormatLibrary


          这个是很久之前写的,去年总结了一下,将其单独提取出来,作为一个开源库放到了GitHub上,然而CPPFormat之类的名字都已经被抢注了,结果只好注册了一个这么蛋疼的名字:CPPFormatLibrary,以下简称FL。

          首先介绍一下这是个什么东西。我们知道,在C++当中要进行格式化字符串,通常采用的是C库函数sprintf或者C++的stringstream,然而两者都有自己的问题,比如C库函数的类型安全问题,sprintf当参数不足,或者参数类型与格式化字符不符是都会发生错误,导致崩溃;而stringstream的效率又明显不行。除此之外,我么还知道boost库有format可以用,然而它效率不高。另外还有国外的大神写过fastformat库,地址:http://fastformat.sourceforge.net/ 。它的问题在于过于庞大,集成不方便,会引入太多你并不需要的东西;同时,它也并未将性能发挥到极限。我写这个FL库最初的灵感也来自于fastformat,也特别感谢它。

          FL与fastformat一样,都致力于解决前面所描述的C++字符串格式化的各种问题,最终采用的方案是.net方案,关于.net的格式化字符串,可以看这篇文章:http://www.cnblogs.com/zyh-nhy/archive/2007/10/11/921240.html  与fastformat想比,FL移除了一些并没有什么用的功能,并进行了功能增强,比如fastformat并不支持{0,5}这样的更细的描述,而FL支持。当然fastformat与FL都没有完全覆盖.net的format,也就是说并不完全等同于.net的格式化,部分功能并未得到支持。

          下面是FL中的测试代码,这个代码展示了最基本的格式化功能:

     1 // Test
     2 #include "Format.hpp"
     3 
     4 #include "Format/ProgressTimer.hpp"
     5 
     6 #define TEST_PERFORMANCE_IN_TOOLS 0
     7 
     8 using namespace FormatLibrary;
     9 
    10 #include <iostream>
    11 #include <vector>
    12 using namespace std;
    13 
    14 void TestProfile()
    15 {
    16     const int TEST_COUNT = 100000;
    17 
    18     {
    19         Profile::ProgressTimer Timer("FL");
    20 
    21         for (int i = 0; i < TEST_COUNT; ++i)
    22         {
    23             string str;
    24             StandardLibrary::FormatTo(str, "{0}--#--{1,8}--#--{2}", 100, -40.2f, " String ");
    25             StandardLibrary::FormatTo(str, "{0}--#--{1,8}--#--{1}", 100, -40.2f);
    26             StandardLibrary::FormatTo(str, "{0}--#--{1,8}--#--{3}", 100, -40.2f, std::string("xxx"));
    27         }
    28     }
    29 
    30 #if !FL_COMPILER_MSVC
    31 #define sprintf_s sprintf
    32 #endif
    33 
    34 #if !TEST_PERFORMANCE_IN_TOOLS
    35     {
    36         Profile::ProgressTimer Timer("CL");
    37 
    38         for (int i = 0; i < TEST_COUNT; ++i)
    39         {
    40             string str;
    41             char szBuf[64];
    42             sprintf_s(szBuf, "%d--#--%8.2f--#--%s", 100, -40.2f, " String ");
    43             str = szBuf;
    44             sprintf_s(szBuf, "%d--#--%8.2f--#--%f", 100, -40.2f, 0.0f);
    45             str = szBuf;
    46             sprintf_s(szBuf, "%d--#--%8.2f--#--%%f", 100, -40.2f);
    47             str = szBuf;
    48         }
    49     }
    50 #endif
    51 }
    52 
    53 #if FL_PLATFORM_HAS_CPP11 && (FL_COMPILER_MSVC||FL_PLATFORM_MACOS)
    54 #include <thread>
    55 
    56 void TestProfileMultiThread()
    57 {
    58     std::thread t0( TestProfile );
    59     std::thread t1( TestProfile );
    60     std::thread t2( TestProfile );
    61 
    62     t0.join();
    63     t1.join();
    64     t2.join();
    65 }
    66 #endif
    67 
    68 int main()
    69 {
    70     StandardLibrary::STLGlobalPatternStorageA Storage;
    71     Utility::TAutoString<char> TestStr;
    72 
    73     const char* pszTest = "{0},xxxd{1:d2}={2,3:d2} !! {{}} {0,-5:d8}";
    74     Storage.LookupPatterns(pszTest, strlen(pszTest));
    75 
    76     std::string str;
    77     StandardLibrary::FormatTo(str, "test{0}", 10);
    78 
    79     StandardLibrary::FormatTo(str, "{0}", char('c'), short(2));
    80 
    81 #if FL_COMPILER_MSVC
    82     StandardLibrary::FormatTo(str, "0x{0:x}", 100, DWORD(100));
    83 #endif
    84 
    85     std::wstring wstr;
    86     StandardLibrary::FormatTo(wstr, L"Test{1}, {2:f4}, {0}, {0,4}", L" X ", 20, -10.005f);
    87 
    88     cout << str << endl;
    89     wcout << wstr << endl;
    90 
    91     TestProfile();
    92     
    93 #if FL_PLATFORM_HAS_CPP11 && (FL_COMPILER_MSVC||FL_PLATFORM_MACOS)
    94     TestProfileMultiThread();
    95 #endif
    96 
    97     return 0;
    98 }

    Windows Visual Studio 2013 Release下的输出:

    0x64
    Test20, -10.0050,  X ,  X
    0x64
    Test20, -10.0050,  X ,  X
    1920 FLElapse:0.0762746
    1920 CLElapse:0.269722
    1636 FLElapse:0.0756153
    7732 FLElapse:0.0766446
    7956 FLElapse:0.0762051
    7956 CLElapse:0.285714
    1636 CLElapse:0.288648
    7732 CLElapse:0.289193

    Mac Xcode Release:

    99
    Test20, -10.0050,  X ,  X 
    18446744073709551615 FLElapse:0.0901681
    18446744073709551615 CLElapse:0.19329
    18446744073709551615 FLElapse:0.147378
    18446744073709551615 FLElapse:0.150375
    18446744073709551615 FLElapse:0.153342
    18446744073709551615 CLElapse:0.303508
    18446744073709551615 CLElapse:0.308418
    18446744073709551615 CLElapse:0.307407

         这只是一个简单的测试,结果并不能覆盖所有情况,然而可以明确的是,FL在提供了:编译期类型安全检查,不定参数,多线程支持,可重入,可乱序等功能的前提下,并不会比C库函数sprintf慢。因此可以认为在使用C++的情况下,始终应该使用FL代替传统的各种格式化字符串的方式以获取更好更安全的代码。

         FL被设计成Header Only的库,这样用起来就更方便了,只需要简单的包含Format.hpp头文件即可获取到所有的功能。同时针对C++ 11做了专门的优化,使得在支持C++ 11的编译器上可以取得更快的运行速度,这是其它库无法比拟的。

         如果你使用的是STL的字符串string或者wstring,那么FL已经内置了对应的支持,所有的适配器都已经默认提供。假如你不是使用的STL,比如UnrealEngine中使用的FString,那么你也可以非常容易的集成FL到自己的项目中。UnrealEngine的FString在集成了FL之后,会多出一个静态的FormatTo函数和一个Format成员函数,它们可以用于使用.net风格产生一个字符串或者直接格式化自己。在项目中也可以找到UnrealEngine的集成代码,非常简单。

         FL已经成功使用Visual Studio,XCode和Codeblocks with gcc进行编译,并支持windows,macos,linux,ios等平台。已经成功用于多个项目。

         项目地址:https://github.com/sczybt/CPPFormatLibrary

         使用git Clone地址:https://github.com/sczybt/CPPFormatLibrary.git

         你也可以直接Download zip

         另外,一个代码库不可能没有bug,如果你发现了问题,可以将测试用例发给我,我会修复之。欢迎大家来使用。

         接下来我会针对这个库提供更多的说明和指导文档。

    2015.10.15

    CPPFormatLibary提升效率的优化原理

    关于优化策略的相关讨论:http://www.cnblogs.com/bodong/p/4800340.html

  • 相关阅读:
    Asp.Net细节性问题精萃(转)
    开发OFFICE插件总结(转)
    校内网开心网数据同步引发的讨论(转)
    C++指针探讨 (三) 成员函数指针 (转)
    C++指针探讨 (二) 函数指针 (转)
    【原创】编程获取PE文件信息的方法(转)
    为.net开发者提供的一份关于存储过程的评论(转)
    C++指针探讨 (一)数据指针 (转)
    如何批量修改PPT字体、大小、颜色(转)
    搜索引擎里的爱人(转)
  • 原文地址:https://www.cnblogs.com/bodong/p/4799676.html
Copyright © 2020-2023  润新知