Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/elfmz/far2l.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelfmz <fenix1905@tut.by>2020-10-18 19:45:30 +0300
committerelfmz <fenix1905@tut.by>2020-10-18 19:45:30 +0300
commitedff7df461c09a6f06ecb3df3a788e770f643fb8 (patch)
treec1f222d04487cb83d70dcfdc09bc6f777cbcdd70
parent73c5a929612480d3d33a5d555c08c856ec2a2fa6 (diff)
cache iconv opensiconv
-rw-r--r--WinPort/CMakeLists.txt1
-rw-r--r--WinPort/src/APIStringCodepages.cpp54
-rw-r--r--WinPort/src/CachedIConv.cpp87
-rw-r--r--WinPort/src/CachedIConv.h26
-rw-r--r--utils/CMakeLists.txt1
-rw-r--r--utils/include/ThreadSpecific.h14
-rw-r--r--utils/include/Threaded.h1
-rw-r--r--utils/src/ThreadSpecific.cpp29
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));
+ }
+}