diff options
author | elfmz <fenix1905@tut.by> | 2020-10-18 19:45:30 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2020-10-18 19:45:30 +0300 |
commit | edff7df461c09a6f06ecb3df3a788e770f643fb8 (patch) | |
tree | c1f222d04487cb83d70dcfdc09bc6f777cbcdd70 | |
parent | 73c5a929612480d3d33a5d555c08c856ec2a2fa6 (diff) |
cache iconv opensiconv
-rw-r--r-- | WinPort/CMakeLists.txt | 1 | ||||
-rw-r--r-- | WinPort/src/APIStringCodepages.cpp | 54 | ||||
-rw-r--r-- | WinPort/src/CachedIConv.cpp | 87 | ||||
-rw-r--r-- | WinPort/src/CachedIConv.h | 26 | ||||
-rw-r--r-- | utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | utils/include/ThreadSpecific.h | 14 | ||||
-rw-r--r-- | utils/include/Threaded.h | 1 | ||||
-rw-r--r-- | utils/src/ThreadSpecific.cpp | 29 |
8 files changed, 170 insertions, 43 deletions
diff --git a/WinPort/CMakeLists.txt b/WinPort/CMakeLists.txt index c0099b03..c97cf749 100644 --- a/WinPort/CMakeLists.txt +++ b/WinPort/CMakeLists.txt @@ -21,6 +21,7 @@ src/APIStringCodepages.cpp src/APIStringMap.cpp src/APISynch.cpp src/APITime.cpp +src/CachedIConv.cpp src/ConsoleBuffer.cpp src/ConsoleInput.cpp src/ConsoleOutput.cpp diff --git a/WinPort/src/APIStringCodepages.cpp b/WinPort/src/APIStringCodepages.cpp index 0615fd0b..52571b77 100644 --- a/WinPort/src/APIStringCodepages.cpp +++ b/WinPort/src/APIStringCodepages.cpp @@ -18,7 +18,7 @@ #include "PathHelpers.h" #include "ConvertUTF.h" -#include <iconv.h> +#include "CachedIConv.h" #define UTF8_INTERNAL_IMPLEMENTATION @@ -245,63 +245,31 @@ template <class CODEUNIT_SRC, class CODEUNIT_DST> } -#if (__WCHAR_MAX__ > 0xffff) -# define CP_ICONV_WCHAR "UTF-32LE" // //IGNORE -#else -# define CP_ICONV_WCHAR "UTF-15LE" // //IGNORE -#endif - -thread_local char g_iconv_codepage_name[20]; - -static const char *iconv_codepage_name(unsigned int page) -{ - switch (page) { - case CP_KOI8R: return "CP_KOI8R-7"; - case CP_UTF8: return "UTF-8"; - case CP_UTF7: return "UTF-7"; - default: { - sprintf(g_iconv_codepage_name, "CP%d", page); - return g_iconv_codepage_name; - } - } -} - static int iconv_cp_mbstowcs(unsigned int page, unsigned int flags, const char *src, size_t srclen, wchar_t *dst, size_t dstlen ) { - // iconv init - iconv_t cd = iconv_open(CP_ICONV_WCHAR, iconv_codepage_name(page)); + try { + CachedIConv cic(false, page); + return iconv_do<char, wchar_t>(cic, flags, src, srclen, dst, dstlen); - if (cd == (iconv_t)-1) { - fprintf(stderr, "iconv_cp_mbstowcs(%u): error %d\n", page, errno); - WINPORT(SetLastError)( ERROR_INVALID_PARAMETER ); + } catch (std::exception &e) { + fprintf(stderr, "iconv_cp_mbstowcs(%u): %s\n", page, e.what()); return 0; } - - int ir = iconv_do<char, wchar_t>(cd, flags, src, srclen, dst, dstlen); - - iconv_close(cd); - - return ir; } static int iconv_cp_wcstombs(unsigned int page, unsigned int flags, const wchar_t *src, size_t srclen, char *dst, size_t dstlen, char replacement_char, LPBOOL replacement_used) { - iconv_t cd = iconv_open(iconv_codepage_name(page), CP_ICONV_WCHAR); + try { + CachedIConv cic(true, page); + return iconv_do<wchar_t, char>(cic, flags, src, srclen, dst, dstlen, replacement_char, replacement_used); - if (cd == (iconv_t)-1) { - fprintf(stderr, "iconv_cp_wcstombs(%u): error %d\n", page, errno); - WINPORT(SetLastError)( ERROR_INVALID_PARAMETER ); + } catch (std::exception &e) { + fprintf(stderr, "iconv_cp_mbstowcs(%u): %s\n", page, e.what()); return 0; } - - int ir = iconv_do<wchar_t, char>(cd, flags, src, srclen, dst, dstlen, replacement_char, replacement_used); - - iconv_close(cd); - - return ir; } /////////////////////////////////// diff --git a/WinPort/src/CachedIConv.cpp b/WinPort/src/CachedIConv.cpp new file mode 100644 index 00000000..9c1c47c0 --- /dev/null +++ b/WinPort/src/CachedIConv.cpp @@ -0,0 +1,87 @@ +#include "WinCompat.h" +#include "WinPort.h" +#include "CachedIConv.h" +#include <utils.h> +#include <ThreadSpecific.h> +#include <stdexcept> + +#if (__WCHAR_MAX__ > 0xffff) +# define CP_ICONV_WCHAR "UTF-32LE" // //IGNORE +#else +# define CP_ICONV_WCHAR "UTF-16LE" // //IGNORE +#endif + +static const char *iconv_codepage_name(uint32_t page, char *tmpbuf) +{ + switch (page) { + case CP_KOI8R: return "CP_KOI8R-7"; + case CP_UTF8: return "UTF-8"; + case CP_UTF7: return "UTF-7"; + default: { + sprintf(tmpbuf, "CP%d", page); + return tmpbuf; + } + } +} + + + +static void CachedIConv_ThreadCleanup(void *p) +{ + if (!p) + return; + + IConvCache *p_icc = (IConvCache *)p; + for (auto &it : *p_icc) { + iconv_close(it.second); + } + delete p_icc; +} + +static ThreadSpecific s_icc_ts(&CachedIConv_ThreadCleanup); + +CachedIConv::CachedIConv(bool wide2mb, uint32_t page) +{ + uint64_t key = page; + if (wide2mb) { + key|= 0x8000000000000000; + } + + _icc = (IConvCache *)s_icc_ts.Get(); + if (!_icc) { + _icc = new IConvCache; + try { + s_icc_ts.Set(_icc); + + } catch (std::exception &) { + delete _icc; + throw; + } + + } else { + auto it = _icc->find(key); + if (it != _icc->end()) { + _cd = it->second; + return; + } + } + + char tmpbuf[32]; + if (wide2mb) { + _cd = iconv_open(iconv_codepage_name(page, tmpbuf), CP_ICONV_WCHAR); + } else { + _cd = iconv_open(CP_ICONV_WCHAR, iconv_codepage_name(page, tmpbuf)); + } + + if (_cd == (iconv_t)-1) { + throw std::runtime_error( + StrPrintf("CachedIConv(%d, %u) - error %d", wide2mb, page, errno)); + } + + _icc->emplace(key, _cd); +} + +CachedIConv::~CachedIConv() +{ + // its already in cache, dont care +} diff --git a/WinPort/src/CachedIConv.h b/WinPort/src/CachedIConv.h new file mode 100644 index 00000000..eac2e024 --- /dev/null +++ b/WinPort/src/CachedIConv.h @@ -0,0 +1,26 @@ +#pragma once +#include <iconv.h> +#include <string> +#include <map> +#include <stdint.h> + +typedef std::map<uint64_t, iconv_t> IConvCache; + +class CachedIConv +{ + IConvCache *_icc; + iconv_t _cd; + + CachedIConv(const CachedIConv&) = delete; + +public: + CachedIConv(bool wide2mb, uint32_t page); + ~CachedIConv(); + + inline operator iconv_t() + { + return _cd; + } +}; + +void CachedIConv_Initialize(); diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index da081eda..3a7f348e 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES src/crc64.c src/ini.c src/TTYRawMode.cpp + src/ThreadSpecific.cpp ) add_library (utils ${SOURCES}) diff --git a/utils/include/ThreadSpecific.h b/utils/include/ThreadSpecific.h new file mode 100644 index 00000000..c82aa5e0 --- /dev/null +++ b/utils/include/ThreadSpecific.h @@ -0,0 +1,14 @@ +#pragma once +#include <pthread.h> + +class ThreadSpecific +{ + pthread_key_t _key; + +public: + ThreadSpecific(void (*destructor)(void*) = nullptr); + ~ThreadSpecific(); + + void *Get(); + void Set(void *v); +}; diff --git a/utils/include/Threaded.h b/utils/include/Threaded.h index bbdfecb9..d4b07d64 100644 --- a/utils/include/Threaded.h +++ b/utils/include/Threaded.h @@ -23,3 +23,4 @@ protected: bool WaitThread(unsigned int msec = (unsigned int)-1); void *GetThreadResult(); }; + diff --git a/utils/src/ThreadSpecific.cpp b/utils/src/ThreadSpecific.cpp new file mode 100644 index 00000000..c2962666 --- /dev/null +++ b/utils/src/ThreadSpecific.cpp @@ -0,0 +1,29 @@ +#include "ThreadSpecific.h" +#include "utils.h" +#include <exception> +#include <stdexcept> + +ThreadSpecific::ThreadSpecific(void (*destructor)(void*)) +{ + int r = pthread_key_create(&_key, destructor); + if (r != 0) { + throw std::runtime_error(StrPrintf("ThreadSpecific: pthread_key_create error %d", r)); + } +} + +ThreadSpecific::~ThreadSpecific() +{ +} + +void *ThreadSpecific::Get() +{ + return pthread_getspecific(_key); +} + +void ThreadSpecific::Set(void *v) +{ + int r = pthread_setspecific(_key, v); + if (r != 0) { + throw std::runtime_error(StrPrintf("ThreadSpecific: pthread_setspecific error %d", r)); + } +} |