diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/modules/libkcpp/include/kcpp_unittest.hpp b/modules/libkcpp/include/kcpp_unittest.hpp new file mode 100644 index 0000000..4bf8954 --- /dev/null +++ b/modules/libkcpp/include/kcpp_unittest.hpp @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP UNITTEST Header File +// +#ifndef KCPP_UNITTEST_HPP +#define KCPP_UNITTEST_HPP + +namespace kcpp +{ + + +} + + +#endif // KCPP_UNITTEST_HPP diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/modules/libkcpp/include/kcpp_unittest.hpp b/modules/libkcpp/include/kcpp_unittest.hpp new file mode 100644 index 0000000..4bf8954 --- /dev/null +++ b/modules/libkcpp/include/kcpp_unittest.hpp @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP UNITTEST Header File +// +#ifndef KCPP_UNITTEST_HPP +#define KCPP_UNITTEST_HPP + +namespace kcpp +{ + + +} + + +#endif // KCPP_UNITTEST_HPP diff --git a/modules/libkcpp/src/kc_memory.cpp b/modules/libkcpp/src/kc_memory.cpp new file mode 100644 index 0000000..d33bced --- /dev/null +++ b/modules/libkcpp/src/kc_memory.cpp @@ -0,0 +1,1224 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール (C++) +// @copyright 2003 - 2023 Nomura Kei +// + +#include +#include +#include +#include +#include + +// 常に本来の malloc, free を利用するため、KCPP_MEMORY_ENABLED を無効化する。 +#ifdef KCPP_MEMORY_ENABLED +#undef KCPP_MEMORY_ENABLED +#endif +#include + + +using namespace kcpp; +namespace kcpp +{ + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryListener + // + + /** + * MemoryListener を構築します。 + */ + MemoryListener::MemoryListener() { + // NOP + } + + + /** + * MemoryListener を破棄します。 + */ + MemoryListener::~MemoryListener() + { + // NOP + } + + + /** + * メモリ確保時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyAllocate([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * メモリ解放時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyFree([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * エラー発生時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyError([[maybe_unused]] const MemoryEntry& entry, [[maybe_unused]] const char* msg) + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntry ユーティリティ (initMemoryEntry) + // + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + entry->file = file; + entry->func = func; + entry->line = line; + entry->size = size; + entry->_mark = mark; + entry->_prev = nullptr; + entry->_next = nullptr; + entry->data = (entry + 1); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntryManager (内部クラス) + // メモリのエントリを管理します。 + // + + /** + * メモリエントリを管理するクラス。 + */ + class MemoryEntryManager + { + public: + static constexpr int MAX_BUFFER_SIZE = 256; + + MemoryEntryManager(); + virtual ~MemoryEntryManager(); + void add(MemoryEntry* entry); + void remove(MemoryEntry* entry); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn); + private: + void dumpBinary(std::ostream& stream, void* data, size_t size, int limit); + void dumpAscii(std::ostream& stream, void* data, size_t size, int limit); + const char* toPaddingString(const char* str, int limit); + const char* toHexString(unsigned char data); + MemoryEntryManager(const MemoryEntryManager& mgr) = delete; + MemoryEntryManager& operator=(const MemoryEntryManager& mgr) = delete; + MemoryEntry head; + MemoryEntry tail; + std::recursive_mutex entryMutex; + char tmpbuf[MAX_BUFFER_SIZE]; + }; + + + /** + * MemoryEntryManager を構築します。 + */ + MemoryEntryManager::MemoryEntryManager() : + head { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + tail { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + entryMutex(), + tmpbuf{ 0 } + { + initMemoryEntry(&head, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + initMemoryEntry(&tail, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + head._prev = head._next = &tail; + tail._prev = tail._next = &head; + } + + + /** + * MemoryEntryManager を破棄します。 + */ + MemoryEntryManager::~MemoryEntryManager() + { + // NOP + } + + + /** + * 指定されたメモリエントリを追加します。 + * + * @param entry 追加するメモリエントリ + */ + void MemoryEntryManager::add(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // [tail] の一つ前に挿入する + entry->_next = &tail; + entry->_prev = tail._prev; + tail._prev->_next = entry; + tail._prev = entry; + } + + + /** + * 指定されたメモリエントリを削除します。 + * + * @param entry 削除するメモリエントリ + */ + void MemoryEntryManager::remove(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // entry の前後を直接リンクさせる + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::entries(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isContinue = true; + for (MemoryEntry* current = head._next; isContinue && (current != &tail); current = current->_next) + { + isContinue = handler(*current); + } + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::freeif(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isFree = false; + for (MemoryEntry* current = head._next; current != &tail; ) + { + isFree = handler(*current); + current = current->_next; + if (isFree) + { + MemoryManager::free(current->_prev->data); + } + } + } + + + /** + * 管理しているメモリエントリをダンプします。 + * + * @param stream ダンプ出力先ストリーム + * @param width 幅 + * @param isDumpBinary バイナリダンプ + * @param isDumpAscii ASCII ダンプ + * @param maxColumn 最大桁数 + */ + void MemoryEntryManager::dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + std::lock_guard lock(entryMutex); + + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分の最大表示桁数を取得する。 + int infoColumn = maxColumn; + infoColumn -= (isDumpBinary) ? (dumpByte * 3) + 2 : 0; + infoColumn -= (isDumpAscii) ? (dumpByte ) + 3 : 0; + if (infoColumn < 0) + { + infoColumn = 0; + } + + // 管理している全メモリエントリをループ + for (MemoryEntry* current = head._next; current != &tail; current = current->_next) + { + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分出力 + std::stringstream ss; + ss << current->file << ":" << current->line << " (size=" << current->size << ")" + << " [func=" << current->func << "]"; + stream << toPaddingString(ss.str().c_str(), infoColumn); + + // 16進数ダンプ + if (isDumpBinary) + { + stream << " | "; + dumpBinary(stream, current->data, current->size, dumpByte); + } + + // ASCII ダンプ + if (isDumpAscii) + { + stream << " | "; + dumpAscii(stream, current->data, current->size, dumpByte); + } + + stream << std::endl; + } + } + + + /** + * 指定されたデータを指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpBinary(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + if (idx != 0) { stream << " "; } + stream << toHexString(dataPtr[idx]); + } + for (; idx < limit; idx++) + { + if (idx != 0) { stream << " "; } + stream << "--"; + } + } + + + /** + * 指定されたデータを ASCII 文字で、指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpAscii(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + stream << static_cast((((0x20 <= dataPtr[idx]) && (dataPtr[idx] < 0x7F)) ? dataPtr[idx] : '.')); + } + for (; idx < limit; idx++) + { + stream << " "; + } + } + + /** + * 指定された文字列を指定された文字数にパディングします。 + * 指定された limit より文字数が多い場合は、limit まで文字列が切り詰められます。 + * + * @param str 文字列 + * @param limit 文字数 + * @return 制限された文字列 + */ + const char* MemoryEntryManager::toPaddingString(const char* str, int limit) + { + int maxLimit = (limit <= (MAX_BUFFER_SIZE - 1)) ? limit : (MAX_BUFFER_SIZE - 1); + int len = std::strlen(str); + if (len < maxLimit) + { + memcpy(tmpbuf, str, len); + memset((tmpbuf + len), ' ', (maxLimit - len)); + } + else + { + memcpy(tmpbuf, str, maxLimit); + } + tmpbuf[maxLimit] = '\0'; + return tmpbuf; + } + + + /** + * 指定されたデータを16進数文字列に変換します。 + * + * @param data 変換するデータ + * @return 16進数文字列 + */ + const char* MemoryEntryManager::toHexString(unsigned char data) + { + static const char* HEX_STRINGS = "0123456789ABCDEF"; + tmpbuf[0] = HEX_STRINGS[(static_cast(data) >> 4) & 0x0F]; + tmpbuf[1] = HEX_STRINGS[ static_cast(data) & 0x0F]; + tmpbuf[2] = '\0'; + return tmpbuf; + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryManager + // メモリ管理 + // + + namespace MemoryManager + { + namespace + { + // ================================================================= + // 内部定数 + // ================================================================= + int const PADDING = sizeof(void*) * 2; + + // ================================================================= + // 内部関数プロトタイプ宣言 + // ================================================================= + std::new_handler getNewHandler(); + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void* allocate(std::size_t size, std::align_val_t align, MemoryMark mark, const char* file, const char* func, int line); + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void deallocate(void* ptr, MemoryMark expectedMark); + + // reallocate から呼び出される関数 + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateInvalidPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + + // deallocate から呼び出される関数 + void deallocateEntry(MemoryEntry* entry); + + + // ================================================================= + // 内部変数 + // ================================================================= + MemoryListener defaultListener; + MemoryListener* listener = &defaultListener; //!< メモリ管理リスナ + MemoryEntryManager entryMgr; + + } + + + // ================================================================= + // new 実施時の情報を一時保持するための変数 + // ================================================================= + thread_local const char* file; //!< ファイル名 + thread_local const char* func; //!< 関数 + thread_local int line; //!< 行番号 + + + /** + * メモリ確保, 解放, エラー発生時に通知を受信するリスナを登録します。 + * + * @param l 登録するリスナ + */ + void setListener(MemoryListener& l) + { + listener = &l; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void entries(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.entries(handler); + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void freeif(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.freeif(handler); + } + + + /** + * 管理しているメモリエントリ情報をダンプします。 + * + * @param stream ダンプ先ストリーム + * @param dumpByte ダンプするバイト数 + * @param isDumpBinary バイナリをダンプする + * @param isDumpAscii アスキーをダンプする + * @param maxColumn 最大表示桁数 + */ + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + entryMgr.dump(stream, dumpByte, isDumpBinary, isDumpAscii, maxColumn); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, const char* func, int line) + { + void* ptr = allocate(size, MEMORY_MARK_ALLOCATED, file, func, line); + return ptr; + } + + + /** + * 指定されたサイズの nmemb 個の要素からなるメモリを確保します。 + * + * @param nmemb 確保する要素数 + * @param size 1要素のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* cmalloc(std::size_t nmemb, std::size_t size, const char* file, const char* func, int line) + { + size_t n = nmemb * size; + void* ptr = allocate(n, MEMORY_MARK_ALLOCATED, file, func, line); + if (ptr != nullptr) + { + std::memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, const char* func, int line) + { + void* nptr = reallocate(ptr, size, MEMORY_MARK_ALLOCATED, file, func, line); + return nptr; + } + + + /** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ + void free(void* ptr) + { + deallocate(ptr, MEMORY_MARK_ALLOCATED); + } + + + namespace + { + // ================================================================= + // 内部関数の実装 + // ================================================================= + + /** + * new_handler を取得します。 + * @return new_handler + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::malloc(size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param align アライメント + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, std::align_val_t align, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::aligned_alloc(static_cast(align), size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * ポインタが nullptr の場合、allocate を呼び出します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + if (ptr == nullptr) + { + return allocate(size, mark, file, func, line); + } + + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + switch (oldEntry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み -> 通常の allocate と同様とする。 + return allocate(size, mark, file, func,line); + case MEMORY_MARK_ALLOCATED: // 管理されたメモリの realloc + return reallocateManagedPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW: // 不正 (new で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // 不正 (new[] で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + default: // 管理外メモリの realloc + return reallocateUnManagedPtr(ptr, size, mark, file, func, line); + } + } + + + /** + * 指定されたポインタの指すメモリ領域を解放します。 + * nullptr の場合何もしません。 + * 管理されたメモリの場合、管理領域を合わせて解放します。 + * 管理外メモリの場合、fee を実行します。 + * + * @param ptr 解放するメモリへのポインタ + * @param expectedMark 期待するメモリ確保情報 + */ + void deallocate(void* ptr, MemoryMark expectedMark) + { + if (ptr == nullptr) + { + return; + } + + MemoryEntry* entry = static_cast(ptr); + entry--; + if (entry->_mark == expectedMark) + { // 期待するメモリ確保情報の場合、そのまま解放する。 + deallocateEntry(entry); + } + else + { // 期待しないメモリ確保情報の場合 + switch (entry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み + // Nothing to do. + break; + case MEMORY_MARK_ALLOCATED: // 管理メモリ + listener->notifyError(*entry, "warning free memory (please use free)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW: // new により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // new[] により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete[])"); + deallocateEntry(entry); + break; + default: // 管理外メモリ + std::free(ptr); + break; + } + } + } + + + /** + * 管理されたメモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + + // メモリのエントリより削除する + entryMgr.remove(oldEntry); + MemoryEntry* entry = static_cast(std::realloc(oldEntry, size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) + { // メモリ確保成功 + // -> 管理領域の情報を更新して、メモリのエントリとして追加する。 + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 管理外メモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + // |<-- 新たな領域 ---------------->| + // +------------+-------------------+ + // | 元々の領域 | 追加分 + 管理領域 | + // +------------+-------------------+ + // ↓ + // ↓memmove で 元々の領域 + 追加分 を、 + // ↓管理領域分を確保した先にコピーする + // ↓ + // +----------+------------+--------+ + // | 管理領域 | 元々の領域 | 追加分 | + // +----------+------------+--------+ + MemoryEntry* entry = static_cast(std::realloc(ptr, size + sizeof(MemoryEntry) + PADDING)); + if (entry != NULL) + { // メモリ確保成功 + // memmove で 元々の領域 + 追加分をコピーして、メモリのエントリとして追加する。 + std::memmove((entry + 1), entry, size); + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 不正なメモリ領域に対する realloc のエラー処理を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ(nullptr 固定) + */ + void* reallocateInvalidPtr([[maybe_unused]] void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + errno = EINVAL; + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate (invalid pointer)"); + return nullptr; + } + + + /** + * 指定されたメモリ管理およびデータ領域を解放します。 + * + * @param entry 解放するメモリ管理領域へのポインタ + */ + void deallocateEntry(MemoryEntry* entry) + { + listener->notifyFree(*entry); + entry->_mark = MEMORY_MARK_DELETED; + entry->size = 0; + entryMgr.remove(entry); + std::free(entry); + } + } + + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// new/delete 演算子のオーバライド +// + +// C++17 (C++1z) 以降の new/delete 演算子 + + +// ============================================================================= +// new 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +// ============================================================================= +// new[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new[] による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + +// ============================================================================= +// delete 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + + +// ============================================================================= +// delete[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete[] により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/modules/libkcpp/include/kcpp_unittest.hpp b/modules/libkcpp/include/kcpp_unittest.hpp new file mode 100644 index 0000000..4bf8954 --- /dev/null +++ b/modules/libkcpp/include/kcpp_unittest.hpp @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP UNITTEST Header File +// +#ifndef KCPP_UNITTEST_HPP +#define KCPP_UNITTEST_HPP + +namespace kcpp +{ + + +} + + +#endif // KCPP_UNITTEST_HPP diff --git a/modules/libkcpp/src/kc_memory.cpp b/modules/libkcpp/src/kc_memory.cpp new file mode 100644 index 0000000..d33bced --- /dev/null +++ b/modules/libkcpp/src/kc_memory.cpp @@ -0,0 +1,1224 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール (C++) +// @copyright 2003 - 2023 Nomura Kei +// + +#include +#include +#include +#include +#include + +// 常に本来の malloc, free を利用するため、KCPP_MEMORY_ENABLED を無効化する。 +#ifdef KCPP_MEMORY_ENABLED +#undef KCPP_MEMORY_ENABLED +#endif +#include + + +using namespace kcpp; +namespace kcpp +{ + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryListener + // + + /** + * MemoryListener を構築します。 + */ + MemoryListener::MemoryListener() { + // NOP + } + + + /** + * MemoryListener を破棄します。 + */ + MemoryListener::~MemoryListener() + { + // NOP + } + + + /** + * メモリ確保時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyAllocate([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * メモリ解放時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyFree([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * エラー発生時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyError([[maybe_unused]] const MemoryEntry& entry, [[maybe_unused]] const char* msg) + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntry ユーティリティ (initMemoryEntry) + // + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + entry->file = file; + entry->func = func; + entry->line = line; + entry->size = size; + entry->_mark = mark; + entry->_prev = nullptr; + entry->_next = nullptr; + entry->data = (entry + 1); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntryManager (内部クラス) + // メモリのエントリを管理します。 + // + + /** + * メモリエントリを管理するクラス。 + */ + class MemoryEntryManager + { + public: + static constexpr int MAX_BUFFER_SIZE = 256; + + MemoryEntryManager(); + virtual ~MemoryEntryManager(); + void add(MemoryEntry* entry); + void remove(MemoryEntry* entry); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn); + private: + void dumpBinary(std::ostream& stream, void* data, size_t size, int limit); + void dumpAscii(std::ostream& stream, void* data, size_t size, int limit); + const char* toPaddingString(const char* str, int limit); + const char* toHexString(unsigned char data); + MemoryEntryManager(const MemoryEntryManager& mgr) = delete; + MemoryEntryManager& operator=(const MemoryEntryManager& mgr) = delete; + MemoryEntry head; + MemoryEntry tail; + std::recursive_mutex entryMutex; + char tmpbuf[MAX_BUFFER_SIZE]; + }; + + + /** + * MemoryEntryManager を構築します。 + */ + MemoryEntryManager::MemoryEntryManager() : + head { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + tail { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + entryMutex(), + tmpbuf{ 0 } + { + initMemoryEntry(&head, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + initMemoryEntry(&tail, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + head._prev = head._next = &tail; + tail._prev = tail._next = &head; + } + + + /** + * MemoryEntryManager を破棄します。 + */ + MemoryEntryManager::~MemoryEntryManager() + { + // NOP + } + + + /** + * 指定されたメモリエントリを追加します。 + * + * @param entry 追加するメモリエントリ + */ + void MemoryEntryManager::add(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // [tail] の一つ前に挿入する + entry->_next = &tail; + entry->_prev = tail._prev; + tail._prev->_next = entry; + tail._prev = entry; + } + + + /** + * 指定されたメモリエントリを削除します。 + * + * @param entry 削除するメモリエントリ + */ + void MemoryEntryManager::remove(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // entry の前後を直接リンクさせる + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::entries(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isContinue = true; + for (MemoryEntry* current = head._next; isContinue && (current != &tail); current = current->_next) + { + isContinue = handler(*current); + } + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::freeif(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isFree = false; + for (MemoryEntry* current = head._next; current != &tail; ) + { + isFree = handler(*current); + current = current->_next; + if (isFree) + { + MemoryManager::free(current->_prev->data); + } + } + } + + + /** + * 管理しているメモリエントリをダンプします。 + * + * @param stream ダンプ出力先ストリーム + * @param width 幅 + * @param isDumpBinary バイナリダンプ + * @param isDumpAscii ASCII ダンプ + * @param maxColumn 最大桁数 + */ + void MemoryEntryManager::dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + std::lock_guard lock(entryMutex); + + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分の最大表示桁数を取得する。 + int infoColumn = maxColumn; + infoColumn -= (isDumpBinary) ? (dumpByte * 3) + 2 : 0; + infoColumn -= (isDumpAscii) ? (dumpByte ) + 3 : 0; + if (infoColumn < 0) + { + infoColumn = 0; + } + + // 管理している全メモリエントリをループ + for (MemoryEntry* current = head._next; current != &tail; current = current->_next) + { + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分出力 + std::stringstream ss; + ss << current->file << ":" << current->line << " (size=" << current->size << ")" + << " [func=" << current->func << "]"; + stream << toPaddingString(ss.str().c_str(), infoColumn); + + // 16進数ダンプ + if (isDumpBinary) + { + stream << " | "; + dumpBinary(stream, current->data, current->size, dumpByte); + } + + // ASCII ダンプ + if (isDumpAscii) + { + stream << " | "; + dumpAscii(stream, current->data, current->size, dumpByte); + } + + stream << std::endl; + } + } + + + /** + * 指定されたデータを指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpBinary(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + if (idx != 0) { stream << " "; } + stream << toHexString(dataPtr[idx]); + } + for (; idx < limit; idx++) + { + if (idx != 0) { stream << " "; } + stream << "--"; + } + } + + + /** + * 指定されたデータを ASCII 文字で、指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpAscii(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + stream << static_cast((((0x20 <= dataPtr[idx]) && (dataPtr[idx] < 0x7F)) ? dataPtr[idx] : '.')); + } + for (; idx < limit; idx++) + { + stream << " "; + } + } + + /** + * 指定された文字列を指定された文字数にパディングします。 + * 指定された limit より文字数が多い場合は、limit まで文字列が切り詰められます。 + * + * @param str 文字列 + * @param limit 文字数 + * @return 制限された文字列 + */ + const char* MemoryEntryManager::toPaddingString(const char* str, int limit) + { + int maxLimit = (limit <= (MAX_BUFFER_SIZE - 1)) ? limit : (MAX_BUFFER_SIZE - 1); + int len = std::strlen(str); + if (len < maxLimit) + { + memcpy(tmpbuf, str, len); + memset((tmpbuf + len), ' ', (maxLimit - len)); + } + else + { + memcpy(tmpbuf, str, maxLimit); + } + tmpbuf[maxLimit] = '\0'; + return tmpbuf; + } + + + /** + * 指定されたデータを16進数文字列に変換します。 + * + * @param data 変換するデータ + * @return 16進数文字列 + */ + const char* MemoryEntryManager::toHexString(unsigned char data) + { + static const char* HEX_STRINGS = "0123456789ABCDEF"; + tmpbuf[0] = HEX_STRINGS[(static_cast(data) >> 4) & 0x0F]; + tmpbuf[1] = HEX_STRINGS[ static_cast(data) & 0x0F]; + tmpbuf[2] = '\0'; + return tmpbuf; + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryManager + // メモリ管理 + // + + namespace MemoryManager + { + namespace + { + // ================================================================= + // 内部定数 + // ================================================================= + int const PADDING = sizeof(void*) * 2; + + // ================================================================= + // 内部関数プロトタイプ宣言 + // ================================================================= + std::new_handler getNewHandler(); + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void* allocate(std::size_t size, std::align_val_t align, MemoryMark mark, const char* file, const char* func, int line); + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void deallocate(void* ptr, MemoryMark expectedMark); + + // reallocate から呼び出される関数 + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateInvalidPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + + // deallocate から呼び出される関数 + void deallocateEntry(MemoryEntry* entry); + + + // ================================================================= + // 内部変数 + // ================================================================= + MemoryListener defaultListener; + MemoryListener* listener = &defaultListener; //!< メモリ管理リスナ + MemoryEntryManager entryMgr; + + } + + + // ================================================================= + // new 実施時の情報を一時保持するための変数 + // ================================================================= + thread_local const char* file; //!< ファイル名 + thread_local const char* func; //!< 関数 + thread_local int line; //!< 行番号 + + + /** + * メモリ確保, 解放, エラー発生時に通知を受信するリスナを登録します。 + * + * @param l 登録するリスナ + */ + void setListener(MemoryListener& l) + { + listener = &l; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void entries(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.entries(handler); + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void freeif(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.freeif(handler); + } + + + /** + * 管理しているメモリエントリ情報をダンプします。 + * + * @param stream ダンプ先ストリーム + * @param dumpByte ダンプするバイト数 + * @param isDumpBinary バイナリをダンプする + * @param isDumpAscii アスキーをダンプする + * @param maxColumn 最大表示桁数 + */ + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + entryMgr.dump(stream, dumpByte, isDumpBinary, isDumpAscii, maxColumn); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, const char* func, int line) + { + void* ptr = allocate(size, MEMORY_MARK_ALLOCATED, file, func, line); + return ptr; + } + + + /** + * 指定されたサイズの nmemb 個の要素からなるメモリを確保します。 + * + * @param nmemb 確保する要素数 + * @param size 1要素のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* cmalloc(std::size_t nmemb, std::size_t size, const char* file, const char* func, int line) + { + size_t n = nmemb * size; + void* ptr = allocate(n, MEMORY_MARK_ALLOCATED, file, func, line); + if (ptr != nullptr) + { + std::memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, const char* func, int line) + { + void* nptr = reallocate(ptr, size, MEMORY_MARK_ALLOCATED, file, func, line); + return nptr; + } + + + /** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ + void free(void* ptr) + { + deallocate(ptr, MEMORY_MARK_ALLOCATED); + } + + + namespace + { + // ================================================================= + // 内部関数の実装 + // ================================================================= + + /** + * new_handler を取得します。 + * @return new_handler + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::malloc(size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param align アライメント + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, std::align_val_t align, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::aligned_alloc(static_cast(align), size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * ポインタが nullptr の場合、allocate を呼び出します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + if (ptr == nullptr) + { + return allocate(size, mark, file, func, line); + } + + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + switch (oldEntry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み -> 通常の allocate と同様とする。 + return allocate(size, mark, file, func,line); + case MEMORY_MARK_ALLOCATED: // 管理されたメモリの realloc + return reallocateManagedPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW: // 不正 (new で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // 不正 (new[] で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + default: // 管理外メモリの realloc + return reallocateUnManagedPtr(ptr, size, mark, file, func, line); + } + } + + + /** + * 指定されたポインタの指すメモリ領域を解放します。 + * nullptr の場合何もしません。 + * 管理されたメモリの場合、管理領域を合わせて解放します。 + * 管理外メモリの場合、fee を実行します。 + * + * @param ptr 解放するメモリへのポインタ + * @param expectedMark 期待するメモリ確保情報 + */ + void deallocate(void* ptr, MemoryMark expectedMark) + { + if (ptr == nullptr) + { + return; + } + + MemoryEntry* entry = static_cast(ptr); + entry--; + if (entry->_mark == expectedMark) + { // 期待するメモリ確保情報の場合、そのまま解放する。 + deallocateEntry(entry); + } + else + { // 期待しないメモリ確保情報の場合 + switch (entry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み + // Nothing to do. + break; + case MEMORY_MARK_ALLOCATED: // 管理メモリ + listener->notifyError(*entry, "warning free memory (please use free)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW: // new により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // new[] により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete[])"); + deallocateEntry(entry); + break; + default: // 管理外メモリ + std::free(ptr); + break; + } + } + } + + + /** + * 管理されたメモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + + // メモリのエントリより削除する + entryMgr.remove(oldEntry); + MemoryEntry* entry = static_cast(std::realloc(oldEntry, size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) + { // メモリ確保成功 + // -> 管理領域の情報を更新して、メモリのエントリとして追加する。 + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 管理外メモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + // |<-- 新たな領域 ---------------->| + // +------------+-------------------+ + // | 元々の領域 | 追加分 + 管理領域 | + // +------------+-------------------+ + // ↓ + // ↓memmove で 元々の領域 + 追加分 を、 + // ↓管理領域分を確保した先にコピーする + // ↓ + // +----------+------------+--------+ + // | 管理領域 | 元々の領域 | 追加分 | + // +----------+------------+--------+ + MemoryEntry* entry = static_cast(std::realloc(ptr, size + sizeof(MemoryEntry) + PADDING)); + if (entry != NULL) + { // メモリ確保成功 + // memmove で 元々の領域 + 追加分をコピーして、メモリのエントリとして追加する。 + std::memmove((entry + 1), entry, size); + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 不正なメモリ領域に対する realloc のエラー処理を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ(nullptr 固定) + */ + void* reallocateInvalidPtr([[maybe_unused]] void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + errno = EINVAL; + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate (invalid pointer)"); + return nullptr; + } + + + /** + * 指定されたメモリ管理およびデータ領域を解放します。 + * + * @param entry 解放するメモリ管理領域へのポインタ + */ + void deallocateEntry(MemoryEntry* entry) + { + listener->notifyFree(*entry); + entry->_mark = MEMORY_MARK_DELETED; + entry->size = 0; + entryMgr.remove(entry); + std::free(entry); + } + } + + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// new/delete 演算子のオーバライド +// + +// C++17 (C++1z) 以降の new/delete 演算子 + + +// ============================================================================= +// new 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +// ============================================================================= +// new[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new[] による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + +// ============================================================================= +// delete 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + + +// ============================================================================= +// delete[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete[] により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + diff --git a/modules/main/Makefile b/modules/main/Makefile index bdd1023..ea1562c 100644 --- a/modules/main/Makefile +++ b/modules/main/Makefile @@ -33,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lkc +LIBS += -L$(TOPDIR)/lib -lkcpp CLEAN_FILES += CLEAN_DIRS += diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/modules/libkcpp/include/kcpp_unittest.hpp b/modules/libkcpp/include/kcpp_unittest.hpp new file mode 100644 index 0000000..4bf8954 --- /dev/null +++ b/modules/libkcpp/include/kcpp_unittest.hpp @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP UNITTEST Header File +// +#ifndef KCPP_UNITTEST_HPP +#define KCPP_UNITTEST_HPP + +namespace kcpp +{ + + +} + + +#endif // KCPP_UNITTEST_HPP diff --git a/modules/libkcpp/src/kc_memory.cpp b/modules/libkcpp/src/kc_memory.cpp new file mode 100644 index 0000000..d33bced --- /dev/null +++ b/modules/libkcpp/src/kc_memory.cpp @@ -0,0 +1,1224 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール (C++) +// @copyright 2003 - 2023 Nomura Kei +// + +#include +#include +#include +#include +#include + +// 常に本来の malloc, free を利用するため、KCPP_MEMORY_ENABLED を無効化する。 +#ifdef KCPP_MEMORY_ENABLED +#undef KCPP_MEMORY_ENABLED +#endif +#include + + +using namespace kcpp; +namespace kcpp +{ + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryListener + // + + /** + * MemoryListener を構築します。 + */ + MemoryListener::MemoryListener() { + // NOP + } + + + /** + * MemoryListener を破棄します。 + */ + MemoryListener::~MemoryListener() + { + // NOP + } + + + /** + * メモリ確保時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyAllocate([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * メモリ解放時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyFree([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * エラー発生時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyError([[maybe_unused]] const MemoryEntry& entry, [[maybe_unused]] const char* msg) + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntry ユーティリティ (initMemoryEntry) + // + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + entry->file = file; + entry->func = func; + entry->line = line; + entry->size = size; + entry->_mark = mark; + entry->_prev = nullptr; + entry->_next = nullptr; + entry->data = (entry + 1); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntryManager (内部クラス) + // メモリのエントリを管理します。 + // + + /** + * メモリエントリを管理するクラス。 + */ + class MemoryEntryManager + { + public: + static constexpr int MAX_BUFFER_SIZE = 256; + + MemoryEntryManager(); + virtual ~MemoryEntryManager(); + void add(MemoryEntry* entry); + void remove(MemoryEntry* entry); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn); + private: + void dumpBinary(std::ostream& stream, void* data, size_t size, int limit); + void dumpAscii(std::ostream& stream, void* data, size_t size, int limit); + const char* toPaddingString(const char* str, int limit); + const char* toHexString(unsigned char data); + MemoryEntryManager(const MemoryEntryManager& mgr) = delete; + MemoryEntryManager& operator=(const MemoryEntryManager& mgr) = delete; + MemoryEntry head; + MemoryEntry tail; + std::recursive_mutex entryMutex; + char tmpbuf[MAX_BUFFER_SIZE]; + }; + + + /** + * MemoryEntryManager を構築します。 + */ + MemoryEntryManager::MemoryEntryManager() : + head { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + tail { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + entryMutex(), + tmpbuf{ 0 } + { + initMemoryEntry(&head, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + initMemoryEntry(&tail, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + head._prev = head._next = &tail; + tail._prev = tail._next = &head; + } + + + /** + * MemoryEntryManager を破棄します。 + */ + MemoryEntryManager::~MemoryEntryManager() + { + // NOP + } + + + /** + * 指定されたメモリエントリを追加します。 + * + * @param entry 追加するメモリエントリ + */ + void MemoryEntryManager::add(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // [tail] の一つ前に挿入する + entry->_next = &tail; + entry->_prev = tail._prev; + tail._prev->_next = entry; + tail._prev = entry; + } + + + /** + * 指定されたメモリエントリを削除します。 + * + * @param entry 削除するメモリエントリ + */ + void MemoryEntryManager::remove(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // entry の前後を直接リンクさせる + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::entries(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isContinue = true; + for (MemoryEntry* current = head._next; isContinue && (current != &tail); current = current->_next) + { + isContinue = handler(*current); + } + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::freeif(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isFree = false; + for (MemoryEntry* current = head._next; current != &tail; ) + { + isFree = handler(*current); + current = current->_next; + if (isFree) + { + MemoryManager::free(current->_prev->data); + } + } + } + + + /** + * 管理しているメモリエントリをダンプします。 + * + * @param stream ダンプ出力先ストリーム + * @param width 幅 + * @param isDumpBinary バイナリダンプ + * @param isDumpAscii ASCII ダンプ + * @param maxColumn 最大桁数 + */ + void MemoryEntryManager::dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + std::lock_guard lock(entryMutex); + + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分の最大表示桁数を取得する。 + int infoColumn = maxColumn; + infoColumn -= (isDumpBinary) ? (dumpByte * 3) + 2 : 0; + infoColumn -= (isDumpAscii) ? (dumpByte ) + 3 : 0; + if (infoColumn < 0) + { + infoColumn = 0; + } + + // 管理している全メモリエントリをループ + for (MemoryEntry* current = head._next; current != &tail; current = current->_next) + { + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分出力 + std::stringstream ss; + ss << current->file << ":" << current->line << " (size=" << current->size << ")" + << " [func=" << current->func << "]"; + stream << toPaddingString(ss.str().c_str(), infoColumn); + + // 16進数ダンプ + if (isDumpBinary) + { + stream << " | "; + dumpBinary(stream, current->data, current->size, dumpByte); + } + + // ASCII ダンプ + if (isDumpAscii) + { + stream << " | "; + dumpAscii(stream, current->data, current->size, dumpByte); + } + + stream << std::endl; + } + } + + + /** + * 指定されたデータを指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpBinary(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + if (idx != 0) { stream << " "; } + stream << toHexString(dataPtr[idx]); + } + for (; idx < limit; idx++) + { + if (idx != 0) { stream << " "; } + stream << "--"; + } + } + + + /** + * 指定されたデータを ASCII 文字で、指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpAscii(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + stream << static_cast((((0x20 <= dataPtr[idx]) && (dataPtr[idx] < 0x7F)) ? dataPtr[idx] : '.')); + } + for (; idx < limit; idx++) + { + stream << " "; + } + } + + /** + * 指定された文字列を指定された文字数にパディングします。 + * 指定された limit より文字数が多い場合は、limit まで文字列が切り詰められます。 + * + * @param str 文字列 + * @param limit 文字数 + * @return 制限された文字列 + */ + const char* MemoryEntryManager::toPaddingString(const char* str, int limit) + { + int maxLimit = (limit <= (MAX_BUFFER_SIZE - 1)) ? limit : (MAX_BUFFER_SIZE - 1); + int len = std::strlen(str); + if (len < maxLimit) + { + memcpy(tmpbuf, str, len); + memset((tmpbuf + len), ' ', (maxLimit - len)); + } + else + { + memcpy(tmpbuf, str, maxLimit); + } + tmpbuf[maxLimit] = '\0'; + return tmpbuf; + } + + + /** + * 指定されたデータを16進数文字列に変換します。 + * + * @param data 変換するデータ + * @return 16進数文字列 + */ + const char* MemoryEntryManager::toHexString(unsigned char data) + { + static const char* HEX_STRINGS = "0123456789ABCDEF"; + tmpbuf[0] = HEX_STRINGS[(static_cast(data) >> 4) & 0x0F]; + tmpbuf[1] = HEX_STRINGS[ static_cast(data) & 0x0F]; + tmpbuf[2] = '\0'; + return tmpbuf; + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryManager + // メモリ管理 + // + + namespace MemoryManager + { + namespace + { + // ================================================================= + // 内部定数 + // ================================================================= + int const PADDING = sizeof(void*) * 2; + + // ================================================================= + // 内部関数プロトタイプ宣言 + // ================================================================= + std::new_handler getNewHandler(); + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void* allocate(std::size_t size, std::align_val_t align, MemoryMark mark, const char* file, const char* func, int line); + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void deallocate(void* ptr, MemoryMark expectedMark); + + // reallocate から呼び出される関数 + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateInvalidPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + + // deallocate から呼び出される関数 + void deallocateEntry(MemoryEntry* entry); + + + // ================================================================= + // 内部変数 + // ================================================================= + MemoryListener defaultListener; + MemoryListener* listener = &defaultListener; //!< メモリ管理リスナ + MemoryEntryManager entryMgr; + + } + + + // ================================================================= + // new 実施時の情報を一時保持するための変数 + // ================================================================= + thread_local const char* file; //!< ファイル名 + thread_local const char* func; //!< 関数 + thread_local int line; //!< 行番号 + + + /** + * メモリ確保, 解放, エラー発生時に通知を受信するリスナを登録します。 + * + * @param l 登録するリスナ + */ + void setListener(MemoryListener& l) + { + listener = &l; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void entries(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.entries(handler); + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void freeif(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.freeif(handler); + } + + + /** + * 管理しているメモリエントリ情報をダンプします。 + * + * @param stream ダンプ先ストリーム + * @param dumpByte ダンプするバイト数 + * @param isDumpBinary バイナリをダンプする + * @param isDumpAscii アスキーをダンプする + * @param maxColumn 最大表示桁数 + */ + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + entryMgr.dump(stream, dumpByte, isDumpBinary, isDumpAscii, maxColumn); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, const char* func, int line) + { + void* ptr = allocate(size, MEMORY_MARK_ALLOCATED, file, func, line); + return ptr; + } + + + /** + * 指定されたサイズの nmemb 個の要素からなるメモリを確保します。 + * + * @param nmemb 確保する要素数 + * @param size 1要素のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* cmalloc(std::size_t nmemb, std::size_t size, const char* file, const char* func, int line) + { + size_t n = nmemb * size; + void* ptr = allocate(n, MEMORY_MARK_ALLOCATED, file, func, line); + if (ptr != nullptr) + { + std::memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, const char* func, int line) + { + void* nptr = reallocate(ptr, size, MEMORY_MARK_ALLOCATED, file, func, line); + return nptr; + } + + + /** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ + void free(void* ptr) + { + deallocate(ptr, MEMORY_MARK_ALLOCATED); + } + + + namespace + { + // ================================================================= + // 内部関数の実装 + // ================================================================= + + /** + * new_handler を取得します。 + * @return new_handler + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::malloc(size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param align アライメント + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, std::align_val_t align, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::aligned_alloc(static_cast(align), size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * ポインタが nullptr の場合、allocate を呼び出します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + if (ptr == nullptr) + { + return allocate(size, mark, file, func, line); + } + + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + switch (oldEntry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み -> 通常の allocate と同様とする。 + return allocate(size, mark, file, func,line); + case MEMORY_MARK_ALLOCATED: // 管理されたメモリの realloc + return reallocateManagedPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW: // 不正 (new で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // 不正 (new[] で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + default: // 管理外メモリの realloc + return reallocateUnManagedPtr(ptr, size, mark, file, func, line); + } + } + + + /** + * 指定されたポインタの指すメモリ領域を解放します。 + * nullptr の場合何もしません。 + * 管理されたメモリの場合、管理領域を合わせて解放します。 + * 管理外メモリの場合、fee を実行します。 + * + * @param ptr 解放するメモリへのポインタ + * @param expectedMark 期待するメモリ確保情報 + */ + void deallocate(void* ptr, MemoryMark expectedMark) + { + if (ptr == nullptr) + { + return; + } + + MemoryEntry* entry = static_cast(ptr); + entry--; + if (entry->_mark == expectedMark) + { // 期待するメモリ確保情報の場合、そのまま解放する。 + deallocateEntry(entry); + } + else + { // 期待しないメモリ確保情報の場合 + switch (entry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み + // Nothing to do. + break; + case MEMORY_MARK_ALLOCATED: // 管理メモリ + listener->notifyError(*entry, "warning free memory (please use free)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW: // new により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // new[] により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete[])"); + deallocateEntry(entry); + break; + default: // 管理外メモリ + std::free(ptr); + break; + } + } + } + + + /** + * 管理されたメモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + + // メモリのエントリより削除する + entryMgr.remove(oldEntry); + MemoryEntry* entry = static_cast(std::realloc(oldEntry, size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) + { // メモリ確保成功 + // -> 管理領域の情報を更新して、メモリのエントリとして追加する。 + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 管理外メモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + // |<-- 新たな領域 ---------------->| + // +------------+-------------------+ + // | 元々の領域 | 追加分 + 管理領域 | + // +------------+-------------------+ + // ↓ + // ↓memmove で 元々の領域 + 追加分 を、 + // ↓管理領域分を確保した先にコピーする + // ↓ + // +----------+------------+--------+ + // | 管理領域 | 元々の領域 | 追加分 | + // +----------+------------+--------+ + MemoryEntry* entry = static_cast(std::realloc(ptr, size + sizeof(MemoryEntry) + PADDING)); + if (entry != NULL) + { // メモリ確保成功 + // memmove で 元々の領域 + 追加分をコピーして、メモリのエントリとして追加する。 + std::memmove((entry + 1), entry, size); + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 不正なメモリ領域に対する realloc のエラー処理を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ(nullptr 固定) + */ + void* reallocateInvalidPtr([[maybe_unused]] void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + errno = EINVAL; + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate (invalid pointer)"); + return nullptr; + } + + + /** + * 指定されたメモリ管理およびデータ領域を解放します。 + * + * @param entry 解放するメモリ管理領域へのポインタ + */ + void deallocateEntry(MemoryEntry* entry) + { + listener->notifyFree(*entry); + entry->_mark = MEMORY_MARK_DELETED; + entry->size = 0; + entryMgr.remove(entry); + std::free(entry); + } + } + + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// new/delete 演算子のオーバライド +// + +// C++17 (C++1z) 以降の new/delete 演算子 + + +// ============================================================================= +// new 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +// ============================================================================= +// new[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new[] による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + +// ============================================================================= +// delete 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + + +// ============================================================================= +// delete[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete[] により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + diff --git a/modules/main/Makefile b/modules/main/Makefile index bdd1023..ea1562c 100644 --- a/modules/main/Makefile +++ b/modules/main/Makefile @@ -33,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lkc +LIBS += -L$(TOPDIR)/lib -lkcpp CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/main/src/main.c b/modules/main/src/main.c deleted file mode 100644 index bdf609e..0000000 --- a/modules/main/src/main.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - - -void compile(void); -void execute(void); - -void compile(void) -{ - printf("compile\n"); -} - -void execute(void) -{ - printf("execute\n"); -} - - -int main(int argc, char* argv[]) -{ - (void) argc; - (void) argv; - compile(); - execute(); - return 0; -} - diff --git a/config.mk b/config.mk index ceb6197..dd4c015 100644 --- a/config.mk +++ b/config.mk @@ -34,7 +34,7 @@ # CXX_VERSION [-std=c++XX|-std=gnu++XX] (XX=03,11,14,17) # C_VERSION = -std=gnu11 -CXX_VERSION = -std=gnu++11 +CXX_VERSION = -std=gnu++17 # # 共通のインクルードパスを指定します。 @@ -55,5 +55,5 @@ CFLAGS += -DKC_MEMORY_ENABLED=1 -CFLAGS += -DKC_MEMORY_DUMP_LEAK=1 +CXXFLAGS += -DKCPP_MEMORY_ENABLED=1 diff --git a/mk/base-cmd.mk b/mk/base-cmd.mk index 4573bf1..f429bcf 100644 --- a/mk/base-cmd.mk +++ b/mk/base-cmd.mk @@ -31,8 +31,10 @@ TAR = tar TOUCH = touch -CC = $(CROSS_COMPILE)clang -CXX = $(CROSS_COMPILE)clang++ +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +#CC = $(CROSS_COMPILE)clang +#CXX = $(CROSS_COMPILE)clang++ RANLIB = $(CROSS_COMPILE)ranlib ADDR2LINE = $(CROSS_COMPILE)addr2line AR = $(CROSS_COMPILE)ar diff --git a/mk/link-a-conf.mk b/mk/link-a-conf.mk index 8a53da6..0e872f3 100644 --- a/mk/link-a-conf.mk +++ b/mk/link-a-conf.mk @@ -7,7 +7,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/mk/link-so-conf.mk b/mk/link-so-conf.mk index 67e86b8..6eb9a6e 100644 --- a/mk/link-so-conf.mk +++ b/mk/link-so-conf.mk @@ -11,7 +11,7 @@ TOP_TARGET = $(addprefix $(TOPDIR)/lib/,$(TARGET)) -HEADER_FILES = $(wildcard include/*.h) +HEADER_FILES = $(wildcard include/*.h) $(wildcard include/*.hpp) TOP_HEADER_FILES = $(addprefix $(TOPDIR)/include/,$(notdir $(HEADER_FILES))) CLEAN_FILES += $(TOP_TARGET) diff --git a/modules/Makefile b/modules/Makefile index 7c1975e..5da5ba6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,8 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libkc main +#SUBDIRS = libkc main +SUBDIRS = libkcpp main USE_SO_VERSION = # ------------------------------------------------------------------------------ diff --git a/modules/libkc/include/kc.h b/modules/libkc/include/kc.h index 5a9aedc..d19f7e8 100644 --- a/modules/libkc/include/kc.h +++ b/modules/libkc/include/kc.h @@ -31,7 +31,7 @@ // ============================================================================= // ERROR // ============================================================================= -#error "suuports C11/C++1 or later" +#error "suuports C11/C++11 or later" #endif // C++11, C11, ERROR diff --git a/modules/libkc/include/kc_memory.hpp b/modules/libkc/include/kc_memory.hpp deleted file mode 100644 index 0602b74..0000000 --- a/modules/libkc/include/kc_memory.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// メモリ管理モジュール ヘッダファイル -// @copyright 2003 - 2023 Nomura Kei -// -#ifndef KC_MEMORY_HPP -#define KC_MEMORY_HPP - -#include - - -//////////////////////////////////////////////////////////////////////////////// -// -// KC_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 -// -#ifdef KC_MEMORY_ENABLED -namespace kc { - -#if (__cplusplus > 201703L) -// C++20 (C++2a) [C++20 は、202002L] -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; - -#elif (__cplusplus >= 201703L) -// C++17 (C++1z) -void* operator new(std::size size); -void* operator new(std::size size, std::align_val_t alignment); -void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; -void* operator new(std::size_t size, void* ptr) noexcept; - -#else -// C++14 (C++1y), C++11 (C++0x) -void* operator new(std::size_t size); -void* operator new(std::size_t size, void* ptr) noexcept; - -#endif - - -extern thread_local const char* memory_file; -extern thread_local const char* memory_func; -extern thread_local int memory_line; - -#define new \ - ((kc::memory_file = __FILE__, \ - kc::memory_func = __func__, \ - kc::memory_line = __LINE__, \ - 0) && 0) ? 0 : new - -} - -#ifdef // KC_MEMORY_ENABLED -#endif // KC_MEMORY_HPP diff --git a/modules/libkc/src/kc_memory.c b/modules/libkc/src/kc_memory.c index 35cf7cc..482ba35 100644 --- a/modules/libkc/src/kc_memory.c +++ b/modules/libkc/src/kc_memory.c @@ -15,16 +15,9 @@ #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif - -// KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 -#ifndef KC_MEMORY_DUMP_LEAK -#define KC_MEMORY_DUMP_LEAK (0) -#endif - #include - //////////////////////////////////////////////////////////////////////////////// // // 定数定義 @@ -60,23 +53,12 @@ // ============================================================================= // メモリ確保/解放 -static void* kc_memory_allocate(size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - -static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, - KcMemoryMark mark, const char* file, const char* func, int line); - +static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); +static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); - static void kc_memory_deallocate_entry(KcMemoryEntry* entry); diff --git a/modules/libkcpp/Makefile b/modules/libkcpp/Makefile new file mode 100644 index 0000000..044f535 --- /dev/null +++ b/modules/libkcpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libkcpp +TARGET = $(NAME).a +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libkcpp/include/kcpp.hpp b/modules/libkcpp/include/kcpp.hpp new file mode 100644 index 0000000..f4048ef --- /dev/null +++ b/modules/libkcpp/include/kcpp.hpp @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP Header File +// +#ifndef KCPP_HPP +#define KCPP_HPP + + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +// ============================================================================= +// C++17 +// ============================================================================= +#include + + +#else +// ============================================================================= +// ERROR +// ============================================================================= +#error "suuports C++17 or later" + + +#endif // C++17, ERROR + +#endif // KCPP_HPP diff --git a/modules/libkcpp/include/kcpp_memory.hpp b/modules/libkcpp/include/kcpp_memory.hpp new file mode 100644 index 0000000..e7f6f38 --- /dev/null +++ b/modules/libkcpp/include/kcpp_memory.hpp @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール ヘッダファイル +// @copyright 2003 - 2023 Nomura Kei +// +#ifndef KCPP_MEMORY_HPP +#define KCPP_MEMORY_HPP + +#include +#include +#include +#include +#include + +#include + + + +namespace kcpp { + + /** + * メモリ状態 + */ + enum MemoryMark + { + MEMORY_MARK_DELETED = 0x55AA0000, + MEMORY_MARK_ALLOCATED = 0x55AA1111, + MEMORY_MARK_ALLOCATED_NEW = 0x55AA2222, + MEMORY_MARK_ALLOCATED_NEW_ARRAY = 0x55AA4444 + }; + + + /** + * メモリエントリ。 + */ + struct MemoryEntry + { + const char* file; //!< メモリ確保ファイル名 + const char* func; //!< メモリ確保関数名 + int line; //!< メモリ確保行番号 + int size; //!< 確保サイズ + MemoryMark _mark; //!< 確保メモリ状態 + MemoryEntry* _prev; //!< 前の管理メモリポインタ + MemoryEntry* _next; //!< 次の管理メモリポインタ + void* data; //!< データ + }; + + + /** + * メモリが確保, 解放, あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * 本リスナを継承したクラスを MemoryManager::setListener にて登録することにより、 + * メモリ確保, 解放, エラー発生時の通知を受信できます。 + * + * リスナの登録は、プログラム開始時に実施してください。 + */ + class MemoryListener + { + public: + MemoryListener(); + virtual ~MemoryListener(); + virtual void notifyAllocate(const MemoryEntry& entry); + virtual void notifyFree(const MemoryEntry& entry); + virtual void notifyError(const MemoryEntry& entry, const char* msg); + }; + + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, int mark, const char* file, const char* func, int line); + + + + /** + * メモリの確保、解放を管理します。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local const char* func; + extern thread_local int line; + + void setListener(MemoryListener& listener); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte = 16, bool isDumpBinary = true, bool isDumpAscii = true, int dumpColumn = 120); + void* malloc ( std::size_t size, const char* file, const char* func, int line); + void* calloc (std::size_t nmemb, std::size_t size, const char* file, const char* func, int line); + void* realloc(void* ptr , std::size_t size, const char* file, const char* func, int line); + void free (void* ptr); + } +} + + +#if (__cplusplus >= 202002L) +// C++20 (C++2a) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP_MEMORY_ENABLED が定義されている場合、メモリ管理が有効となります。 +// +// +#ifdef KCPP_MEMORY_ENABLED + +// C++17 (C++1z) 以降の new/delete 演算子 +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 +// +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// +// (A) 配置 new による記憶域確保 (あらかじめ用意したメモリに対してインスタンスを割り当てる) +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; + + +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 +// +// 以下については、メモリ管理外としてオーバーライドしない。 +// (A) 配置 new で確保された記憶域の開放 +// void operator delete(void* ptr, void*) noexcept; +// void operator delete[](void* ptr, void*) noexcept; +// +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::align_val_t alignment) noexcept; +void operator delete(void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +void operator delete[](void* ptr) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::align_val_t alignment) noexcept; +void operator delete[](void* ptr, std::align_val_t alignement, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept; + +#define new \ + ((kcpp::MemoryManager::file = __FILE__, \ + kcpp::MemoryManager::func = __func__, \ + kcpp::MemoryManager::line = __LINE__, \ + 0) && 0) ? 0 : new + +#define malloc(size) kcpp::MemoryManager::malloc ( size, __FILE__, __func__, __LINE__) +#define calloc(nmemb, size) kcpp::MemoryManager::calloc (nmemb, size, __FILE__, __func__, __LINE__) +#define realloc(ptr, size) kcpp::MemoryManager::realloc(ptr , size, __FILE__, __func__, __LINE__) +#define free(ptr) kcpp::MemoryManager::free (ptr) + +#else +#include +#include + +#endif // KCPP_MEMORY_ENABLED + + +#endif // KC_MEMORY_HPP diff --git a/modules/libkcpp/include/kcpp_unittest.hpp b/modules/libkcpp/include/kcpp_unittest.hpp new file mode 100644 index 0000000..4bf8954 --- /dev/null +++ b/modules/libkcpp/include/kcpp_unittest.hpp @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// KCPP UNITTEST Header File +// +#ifndef KCPP_UNITTEST_HPP +#define KCPP_UNITTEST_HPP + +namespace kcpp +{ + + +} + + +#endif // KCPP_UNITTEST_HPP diff --git a/modules/libkcpp/src/kc_memory.cpp b/modules/libkcpp/src/kc_memory.cpp new file mode 100644 index 0000000..d33bced --- /dev/null +++ b/modules/libkcpp/src/kc_memory.cpp @@ -0,0 +1,1224 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理モジュール (C++) +// @copyright 2003 - 2023 Nomura Kei +// + +#include +#include +#include +#include +#include + +// 常に本来の malloc, free を利用するため、KCPP_MEMORY_ENABLED を無効化する。 +#ifdef KCPP_MEMORY_ENABLED +#undef KCPP_MEMORY_ENABLED +#endif +#include + + +using namespace kcpp; +namespace kcpp +{ + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryListener + // + + /** + * MemoryListener を構築します。 + */ + MemoryListener::MemoryListener() { + // NOP + } + + + /** + * MemoryListener を破棄します。 + */ + MemoryListener::~MemoryListener() + { + // NOP + } + + + /** + * メモリ確保時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyAllocate([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * メモリ解放時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyFree([[maybe_unused]] const MemoryEntry& entry) + { + // NOP + } + + + /** + * エラー発生時に呼び出されます。 + * + * @param entry メモリエントリ(未使用) + */ + void MemoryListener::notifyError([[maybe_unused]] const MemoryEntry& entry, [[maybe_unused]] const char* msg) + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntry ユーティリティ (initMemoryEntry) + // + + /** + * メモリエントリに指定されたパラメータを設定、初期化します。 + * + * @param entry 初期化設定するメモリエントリ + * @param size 確保サイズ + * @param mark 確保メモリ状態 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + */ + void initMemoryEntry(MemoryEntry* entry, + std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + entry->file = file; + entry->func = func; + entry->line = line; + entry->size = size; + entry->_mark = mark; + entry->_prev = nullptr; + entry->_next = nullptr; + entry->data = (entry + 1); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryEntryManager (内部クラス) + // メモリのエントリを管理します。 + // + + /** + * メモリエントリを管理するクラス。 + */ + class MemoryEntryManager + { + public: + static constexpr int MAX_BUFFER_SIZE = 256; + + MemoryEntryManager(); + virtual ~MemoryEntryManager(); + void add(MemoryEntry* entry); + void remove(MemoryEntry* entry); + void entries(bool (*handler)(const MemoryEntry& entry)); + void freeif(bool (*handler)(const MemoryEntry& entry)); + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn); + private: + void dumpBinary(std::ostream& stream, void* data, size_t size, int limit); + void dumpAscii(std::ostream& stream, void* data, size_t size, int limit); + const char* toPaddingString(const char* str, int limit); + const char* toHexString(unsigned char data); + MemoryEntryManager(const MemoryEntryManager& mgr) = delete; + MemoryEntryManager& operator=(const MemoryEntryManager& mgr) = delete; + MemoryEntry head; + MemoryEntry tail; + std::recursive_mutex entryMutex; + char tmpbuf[MAX_BUFFER_SIZE]; + }; + + + /** + * MemoryEntryManager を構築します。 + */ + MemoryEntryManager::MemoryEntryManager() : + head { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + tail { nullptr, nullptr, 0, 0, MEMORY_MARK_DELETED, nullptr, nullptr, nullptr }, + entryMutex(), + tmpbuf{ 0 } + { + initMemoryEntry(&head, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + initMemoryEntry(&tail, 0, MEMORY_MARK_DELETED, nullptr, nullptr, 0); + head._prev = head._next = &tail; + tail._prev = tail._next = &head; + } + + + /** + * MemoryEntryManager を破棄します。 + */ + MemoryEntryManager::~MemoryEntryManager() + { + // NOP + } + + + /** + * 指定されたメモリエントリを追加します。 + * + * @param entry 追加するメモリエントリ + */ + void MemoryEntryManager::add(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // [tail] の一つ前に挿入する + entry->_next = &tail; + entry->_prev = tail._prev; + tail._prev->_next = entry; + tail._prev = entry; + } + + + /** + * 指定されたメモリエントリを削除します。 + * + * @param entry 削除するメモリエントリ + */ + void MemoryEntryManager::remove(MemoryEntry* entry) + { + std::lock_guard lock(entryMutex); + + // entry の前後を直接リンクさせる + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::entries(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isContinue = true; + for (MemoryEntry* current = head._next; isContinue && (current != &tail); current = current->_next) + { + isContinue = handler(*current); + } + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void MemoryEntryManager::freeif(bool (*handler)(const MemoryEntry& entry)) + { + std::lock_guard lock(entryMutex); + + // 管理している全メモリエントリをループ + // handler が false の場合は、停止する。 + bool isFree = false; + for (MemoryEntry* current = head._next; current != &tail; ) + { + isFree = handler(*current); + current = current->_next; + if (isFree) + { + MemoryManager::free(current->_prev->data); + } + } + } + + + /** + * 管理しているメモリエントリをダンプします。 + * + * @param stream ダンプ出力先ストリーム + * @param width 幅 + * @param isDumpBinary バイナリダンプ + * @param isDumpAscii ASCII ダンプ + * @param maxColumn 最大桁数 + */ + void MemoryEntryManager::dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + std::lock_guard lock(entryMutex); + + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分の最大表示桁数を取得する。 + int infoColumn = maxColumn; + infoColumn -= (isDumpBinary) ? (dumpByte * 3) + 2 : 0; + infoColumn -= (isDumpAscii) ? (dumpByte ) + 3 : 0; + if (infoColumn < 0) + { + infoColumn = 0; + } + + // 管理している全メモリエントリをループ + for (MemoryEntry* current = head._next; current != &tail; current = current->_next) + { + // ファイル名:行番号 (size=サイズ) [func=関数名] 部分出力 + std::stringstream ss; + ss << current->file << ":" << current->line << " (size=" << current->size << ")" + << " [func=" << current->func << "]"; + stream << toPaddingString(ss.str().c_str(), infoColumn); + + // 16進数ダンプ + if (isDumpBinary) + { + stream << " | "; + dumpBinary(stream, current->data, current->size, dumpByte); + } + + // ASCII ダンプ + if (isDumpAscii) + { + stream << " | "; + dumpAscii(stream, current->data, current->size, dumpByte); + } + + stream << std::endl; + } + } + + + /** + * 指定されたデータを指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpBinary(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + if (idx != 0) { stream << " "; } + stream << toHexString(dataPtr[idx]); + } + for (; idx < limit; idx++) + { + if (idx != 0) { stream << " "; } + stream << "--"; + } + } + + + /** + * 指定されたデータを ASCII 文字で、指定されたストリームにダンプします。 + * + * @param stream 出力先ストリーム + * @param data ダンプするデータのポインタ + * @param size ダンプするデータのサイズ + * @param limit ダンプする最大数 + */ + void MemoryEntryManager::dumpAscii(std::ostream& stream, void* data, size_t size, int limit) + { + unsigned char* dataPtr = static_cast(data); + int dataLen = (static_cast(size) < limit) ? static_cast(size) : limit; + int idx = 0; + for (; idx < dataLen; idx++) + { + stream << static_cast((((0x20 <= dataPtr[idx]) && (dataPtr[idx] < 0x7F)) ? dataPtr[idx] : '.')); + } + for (; idx < limit; idx++) + { + stream << " "; + } + } + + /** + * 指定された文字列を指定された文字数にパディングします。 + * 指定された limit より文字数が多い場合は、limit まで文字列が切り詰められます。 + * + * @param str 文字列 + * @param limit 文字数 + * @return 制限された文字列 + */ + const char* MemoryEntryManager::toPaddingString(const char* str, int limit) + { + int maxLimit = (limit <= (MAX_BUFFER_SIZE - 1)) ? limit : (MAX_BUFFER_SIZE - 1); + int len = std::strlen(str); + if (len < maxLimit) + { + memcpy(tmpbuf, str, len); + memset((tmpbuf + len), ' ', (maxLimit - len)); + } + else + { + memcpy(tmpbuf, str, maxLimit); + } + tmpbuf[maxLimit] = '\0'; + return tmpbuf; + } + + + /** + * 指定されたデータを16進数文字列に変換します。 + * + * @param data 変換するデータ + * @return 16進数文字列 + */ + const char* MemoryEntryManager::toHexString(unsigned char data) + { + static const char* HEX_STRINGS = "0123456789ABCDEF"; + tmpbuf[0] = HEX_STRINGS[(static_cast(data) >> 4) & 0x0F]; + tmpbuf[1] = HEX_STRINGS[ static_cast(data) & 0x0F]; + tmpbuf[2] = '\0'; + return tmpbuf; + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // MemoryManager + // メモリ管理 + // + + namespace MemoryManager + { + namespace + { + // ================================================================= + // 内部定数 + // ================================================================= + int const PADDING = sizeof(void*) * 2; + + // ================================================================= + // 内部関数プロトタイプ宣言 + // ================================================================= + std::new_handler getNewHandler(); + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void* allocate(std::size_t size, std::align_val_t align, MemoryMark mark, const char* file, const char* func, int line); + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line); + void deallocate(void* ptr, MemoryMark expectedMark); + + // reallocate から呼び出される関数 + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + void* reallocateInvalidPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line); + + // deallocate から呼び出される関数 + void deallocateEntry(MemoryEntry* entry); + + + // ================================================================= + // 内部変数 + // ================================================================= + MemoryListener defaultListener; + MemoryListener* listener = &defaultListener; //!< メモリ管理リスナ + MemoryEntryManager entryMgr; + + } + + + // ================================================================= + // new 実施時の情報を一時保持するための変数 + // ================================================================= + thread_local const char* file; //!< ファイル名 + thread_local const char* func; //!< 関数 + thread_local int line; //!< 行番号 + + + /** + * メモリ確保, 解放, エラー発生時に通知を受信するリスナを登録します。 + * + * @param l 登録するリスナ + */ + void setListener(MemoryListener& l) + { + listener = &l; + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が false の場合、呼び出しを終了します。 + * + * @param handler ハンドラ + */ + void entries(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.entries(handler); + } + + + /** + * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 + * ハンドラの戻り値が true の場合、該当するメモリを解放します。 + * new で確保したメモリが解放される際、デストラクタは呼び出されないため注意ください。 + * + * @param handler ハンドラ + */ + void freeif(bool (*handler)(const MemoryEntry& entry)) + { + entryMgr.freeif(handler); + } + + + /** + * 管理しているメモリエントリ情報をダンプします。 + * + * @param stream ダンプ先ストリーム + * @param dumpByte ダンプするバイト数 + * @param isDumpBinary バイナリをダンプする + * @param isDumpAscii アスキーをダンプする + * @param maxColumn 最大表示桁数 + */ + void dump(std::ostream& stream, int dumpByte, bool isDumpBinary, bool isDumpAscii, int maxColumn) + { + entryMgr.dump(stream, dumpByte, isDumpBinary, isDumpAscii, maxColumn); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, const char* func, int line) + { + void* ptr = allocate(size, MEMORY_MARK_ALLOCATED, file, func, line); + return ptr; + } + + + /** + * 指定されたサイズの nmemb 個の要素からなるメモリを確保します。 + * + * @param nmemb 確保する要素数 + * @param size 1要素のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* cmalloc(std::size_t nmemb, std::size_t size, const char* file, const char* func, int line) + { + size_t n = nmemb * size; + void* ptr = allocate(n, MEMORY_MARK_ALLOCATED, file, func, line); + if (ptr != nullptr) + { + std::memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, const char* func, int line) + { + void* nptr = reallocate(ptr, size, MEMORY_MARK_ALLOCATED, file, func, line); + return nptr; + } + + + /** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ + void free(void* ptr) + { + deallocate(ptr, MEMORY_MARK_ALLOCATED); + } + + + namespace + { + // ================================================================= + // 内部関数の実装 + // ================================================================= + + /** + * new_handler を取得します。 + * @return new_handler + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::malloc(size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + /** + * 指定されたサイズのメモリを確保します。 + * + * @param align アライメント + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* allocate(std::size_t size, std::align_val_t align, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast(std::aligned_alloc(static_cast(align), size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { // メモリ確保失敗 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't allocate"); + return nullptr; + } + } + + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + + + + /** + * 指定されたポインタが指すメモリサイズを変更します。 + * ポインタが nullptr の場合、allocate を呼び出します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocate(void* ptr, std::size_t size, MemoryMark mark, const char* file, const char* func, int line) + { + if (ptr == nullptr) + { + return allocate(size, mark, file, func, line); + } + + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + switch (oldEntry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み -> 通常の allocate と同様とする。 + return allocate(size, mark, file, func,line); + case MEMORY_MARK_ALLOCATED: // 管理されたメモリの realloc + return reallocateManagedPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW: // 不正 (new で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // 不正 (new[] で確保されたメモリへの realloc) + return reallocateInvalidPtr(ptr, size, mark, file, func, line); + default: // 管理外メモリの realloc + return reallocateUnManagedPtr(ptr, size, mark, file, func, line); + } + } + + + /** + * 指定されたポインタの指すメモリ領域を解放します。 + * nullptr の場合何もしません。 + * 管理されたメモリの場合、管理領域を合わせて解放します。 + * 管理外メモリの場合、fee を実行します。 + * + * @param ptr 解放するメモリへのポインタ + * @param expectedMark 期待するメモリ確保情報 + */ + void deallocate(void* ptr, MemoryMark expectedMark) + { + if (ptr == nullptr) + { + return; + } + + MemoryEntry* entry = static_cast(ptr); + entry--; + if (entry->_mark == expectedMark) + { // 期待するメモリ確保情報の場合、そのまま解放する。 + deallocateEntry(entry); + } + else + { // 期待しないメモリ確保情報の場合 + switch (entry->_mark) + { + case MEMORY_MARK_DELETED: // 削除済み + // Nothing to do. + break; + case MEMORY_MARK_ALLOCATED: // 管理メモリ + listener->notifyError(*entry, "warning free memory (please use free)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW: // new により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete)"); + deallocateEntry(entry); + break; + case MEMORY_MARK_ALLOCATED_NEW_ARRAY: // new[] により確保されたメモリ + listener->notifyError(*entry, "warning free memory (please use delete[])"); + deallocateEntry(entry); + break; + default: // 管理外メモリ + std::free(ptr); + break; + } + } + } + + + /** + * 管理されたメモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + MemoryEntry* oldEntry = static_cast(ptr); + oldEntry--; + + // メモリのエントリより削除する + entryMgr.remove(oldEntry); + MemoryEntry* entry = static_cast(std::realloc(oldEntry, size + sizeof(MemoryEntry) + PADDING)); + if (entry != nullptr) + { // メモリ確保成功 + // -> 管理領域の情報を更新して、メモリのエントリとして追加する。 + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 管理外メモリ領域に対する realloc を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ + */ + void* reallocateUnManagedPtr(void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + // |<-- 新たな領域 ---------------->| + // +------------+-------------------+ + // | 元々の領域 | 追加分 + 管理領域 | + // +------------+-------------------+ + // ↓ + // ↓memmove で 元々の領域 + 追加分 を、 + // ↓管理領域分を確保した先にコピーする + // ↓ + // +----------+------------+--------+ + // | 管理領域 | 元々の領域 | 追加分 | + // +----------+------------+--------+ + MemoryEntry* entry = static_cast(std::realloc(ptr, size + sizeof(MemoryEntry) + PADDING)); + if (entry != NULL) + { // メモリ確保成功 + // memmove で 元々の領域 + 追加分をコピーして、メモリのエントリとして追加する。 + std::memmove((entry + 1), entry, size); + initMemoryEntry(entry, size, mark, file, func, line); + entryMgr.add(entry); + listener->notifyAllocate(*entry); + return (entry->data); + } + else + { // メモリ確保失敗 + // エラーハンドラを実行して nullptr を返す。 + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate"); + return nullptr; + } + } + + + /** + * 不正なメモリ領域に対する realloc のエラー処理を実施します。 + * + * @param ptr メモリサイズを変更するポインタ + * @param size 変更後のメモリサイズ + * @param mark メモリ確保情報 + * @param file メモリ確保ファイル名 + * @param func メモリ確保関数名 + * @param line メモリ確保行番号 + * @return 確保したメモリへのポインタ(nullptr 固定) + */ + void* reallocateInvalidPtr([[maybe_unused]] void* ptr, std::size_t size, + MemoryMark mark, const char* file, const char* func, int line) + { + errno = EINVAL; + MemoryEntry errorEntry; + initMemoryEntry(&errorEntry, size, mark, file, func, line); + listener->notifyError(errorEntry, "can't reallocate (invalid pointer)"); + return nullptr; + } + + + /** + * 指定されたメモリ管理およびデータ領域を解放します。 + * + * @param entry 解放するメモリ管理領域へのポインタ + */ + void deallocateEntry(MemoryEntry* entry) + { + listener->notifyFree(*entry); + entry->_mark = MEMORY_MARK_DELETED; + entry->size = 0; + entryMgr.remove(entry); + std::free(entry); + } + } + + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// new/delete 演算子のオーバライド +// + +// C++17 (C++1z) 以降の new/delete 演算子 + + +// ============================================================================= +// new 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +// ============================================================================= +// new[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域確保 +// (2) 例外送出なしで記憶域確保 +// (3) デフォルトより大きいアライメント要求の記憶域確保 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域確保 + +/** + * new[] による記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size) +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] による例外送出なしでの記憶域確保。 + * + * @param size 確保するメモリサイズ + */ +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment) +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + if (p == nullptr) + { + throw std::bad_alloc(); + } + return p; +} + + +/** + * new[] によるデフォルトより大きいアライメント要求の記憶域確保。 + * + * @param size 確保するメモリサイズ + * @param alignment アライメント + */ +NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = MemoryManager::allocate( + size, + alignment, + MEMORY_MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::file, + MemoryManager::func, + MemoryManager::line); + return p; +} + +// ============================================================================= +// delete 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + +/** + * delete により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete(void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW); +} + + + +// ============================================================================= +// delete[] 演算子 +// ============================================================================= +// 下記、順に +// (1) 記憶域解放 +// (2) 例外送出なしで確保された記憶域解放 +// (3) デフォルトより大きいアライメント要求の記憶域解放 +// (4) 例外送出なしでデフォルトより大きいアライメント要求の記憶域解放 +// (5) オブジェクトサイズが判明している記憶域解放 +// (6) オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域解放 + + +/** + * delete[] により、記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外送出なしで確保された記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void operator delete[](void* ptr, const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、デフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、例外創出なしでデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::align_val_t alignement, [[maybe_unused]] const std::nothrow_t&) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明している記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param size サイズ + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + + +/** + * delete[] により、オブジェクトサイズが判明しているデフォルトより大きいアライメント要求の記憶域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + * @param alignment アライメント + */ +void operator delete[](void* ptr, [[maybe_unused]] std::size_t size, [[maybe_unused]] std::align_val_t alignment) noexcept +{ + MemoryManager::deallocate(ptr, MEMORY_MARK_ALLOCATED_NEW_ARRAY); +} + diff --git a/modules/main/Makefile b/modules/main/Makefile index bdd1023..ea1562c 100644 --- a/modules/main/Makefile +++ b/modules/main/Makefile @@ -33,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lkc +LIBS += -L$(TOPDIR)/lib -lkcpp CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/main/src/main.c b/modules/main/src/main.c deleted file mode 100644 index bdf609e..0000000 --- a/modules/main/src/main.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - - -void compile(void); -void execute(void); - -void compile(void) -{ - printf("compile\n"); -} - -void execute(void) -{ - printf("execute\n"); -} - - -int main(int argc, char* argv[]) -{ - (void) argc; - (void) argv; - compile(); - execute(); - return 0; -} - diff --git a/modules/main/src/main.cpp b/modules/main/src/main.cpp new file mode 100644 index 0000000..0dc5529 --- /dev/null +++ b/modules/main/src/main.cpp @@ -0,0 +1,94 @@ +#include + +#include +#include + + +class MyListener : public kcpp::MemoryListener +{ + public: + MyListener() {} + ~MyListener() {} + void notifyError(const kcpp::MemoryEntry& entry, const char* msg) + { + std::cout << entry.file << ":" << entry.line << "(" << entry.func << "):[size=" << entry.size << "] " + << msg << std::endl; + } + +}; + +bool handler(const kcpp::MemoryEntry& entry) +{ + std::cout << "# " << entry.file << ":" << entry.line << ":(" << entry.size << ")" << std::endl; + return false; +} + +struct alignas(256) OverAligned { + int val[8192]; + char cval[8192]; +}; +int main() +{ + + MyListener listener; + kcpp::MemoryManager::setListener(listener); + + char* tmp1 = new char; + char* tmp2 = new (std::nothrow) char; + OverAligned* tmp3 = new OverAligned; + tmp3->val[0] = 10; + tmp3->val[8000] = 8010; + tmp3->cval[0] = 'A'; + tmp3->cval[1] = '\0'; + std::cout << tmp3->cval << std::endl; + char* tmp4 = new char[5]; + tmp4[0] = 'X'; + tmp4[1] = 'Y'; + tmp4[2] = 'Z'; + tmp4[3] = '\0'; + char* ptr = static_cast(malloc(10)); + char* ptr2 = static_cast(malloc(20)); + char* ptr3 = static_cast(realloc(ptr2, 15)); + char* ptr4 = static_cast(realloc(tmp1, 55)); + +std::cout << "#####################################" << std::endl; +// kcpp::MemoryManager::entries(handler); + kcpp::MemoryManager::dump(std::cout, 4, true, true, 80); //, 100, true, true); +std::cout << "#####################################" << std::endl; + kcpp::MemoryManager::freeif(handler); +std::cout << "#####################################" << std::endl; + +// free(ptr3); +std::cout << "-- 1" << std::endl; + free(ptr4); +std::cout << "-- 2" << std::endl; + free(tmp2); +std::cout << "-- 3" << std::endl; + + std::cout << "========== delete OverAligned" << std::endl; + delete tmp3; + std::cout << "========== END delete OverAligned" << std::endl; +// operator delete(tmp3); + + std::cout << tmp4 << std::endl; + + std::cout << "========== delete tmp4[5]" << std::endl; + delete[] tmp4; + std::cout << "========== END delete tmp4[5]" << std::endl; + + (void)(ptr); + (void)(ptr2); + (void)(ptr3); + (void)(ptr4); + + char* tmp5 = new char[100]; + tmp5[0] = 'A'; + tmp5[1] = '\0'; + std::cout << tmp5[0] << std::endl; + delete [] tmp5; + + + return 0; + +} +