From ff932dba10822b807d6cb12aaf6e27ff406ef7a8 Mon Sep 17 00:00:00 2001 From: jyelon Date: Fri, 25 Feb 2022 19:57:23 -0500 Subject: [PATCH 1/3] More work on moving engine into dlmalloc heap --- luprex/core/cpp/animqueue.hpp | 2 +- luprex/core/cpp/debugcollector.cpp | 4 +- luprex/core/cpp/debugcollector.hpp | 7 +- luprex/core/cpp/drivenengine.cpp | 36 +++--- luprex/core/cpp/drivenengine.hpp | 56 +++++---- luprex/core/cpp/driver-common.cpp | 52 ++++----- luprex/core/cpp/driver-linux.cpp | 22 ++-- luprex/core/cpp/driver-mingw.cpp | 26 ++--- luprex/core/cpp/driver-util.cpp | 9 +- luprex/core/cpp/driver-util.hpp | 4 +- luprex/core/cpp/eng-tests.cpp | 25 +--- luprex/core/cpp/eng-tests.hpp | 9 -- luprex/core/cpp/idalloc.cpp | 3 +- luprex/core/cpp/idalloc.hpp | 3 +- luprex/core/cpp/lpxclient.cpp | 8 +- luprex/core/cpp/lpxclient.hpp | 4 - luprex/core/cpp/lpxserver.cpp | 12 +- luprex/core/cpp/lpxserver.hpp | 4 - luprex/core/cpp/luaconsole.cpp | 4 +- luprex/core/cpp/luasnap.cpp | 2 +- luprex/core/cpp/luastack.cpp | 51 ++++----- luprex/core/cpp/luastack.hpp | 19 ++-- luprex/core/cpp/planemap.cpp | 2 +- luprex/core/cpp/pprint.cpp | 9 +- luprex/core/cpp/pprint.hpp | 8 +- luprex/core/cpp/printbuffer.cpp | 6 +- luprex/core/cpp/printbuffer.hpp | 11 +- luprex/core/cpp/sched.cpp | 3 +- luprex/core/cpp/source.cpp | 29 +++-- luprex/core/cpp/streambuffer.cpp | 6 +- luprex/core/cpp/streambuffer.hpp | 12 +- luprex/core/cpp/textgame.cpp | 7 +- luprex/core/cpp/two-mallocs.hpp | 144 +++++++++++++++++------- luprex/core/cpp/util.cpp | 14 +-- luprex/core/cpp/util.hpp | 32 +++--- luprex/core/cpp/world-accessor.cpp | 6 +- luprex/core/cpp/world-core.cpp | 6 +- luprex/core/cpp/world-testing.cpp | 2 +- luprex/core/cpp/world.hpp | 13 ++- luprex/core/wrap/mkstub.py | 3 - luprex/core/wrap/wrap-algorithm.hpp | 13 --- luprex/core/wrap/wrap-deque.hpp | 7 +- luprex/core/wrap/wrap-map.hpp | 15 +-- luprex/core/wrap/wrap-memory.hpp | 21 ---- luprex/core/wrap/wrap-ostream.hpp | 15 --- luprex/core/wrap/wrap-set.hpp | 11 +- luprex/core/wrap/wrap-sstream.hpp | 8 +- luprex/core/wrap/wrap-string.hpp | 8 +- luprex/core/wrap/wrap-unordered-map.hpp | 19 +--- luprex/core/wrap/wrap-unordered-set.hpp | 15 +-- luprex/core/wrap/wrap-utility.hpp | 21 ---- luprex/core/wrap/wrap-vector.hpp | 7 +- 52 files changed, 351 insertions(+), 484 deletions(-) delete mode 100644 luprex/core/wrap/wrap-algorithm.hpp delete mode 100644 luprex/core/wrap/wrap-memory.hpp delete mode 100644 luprex/core/wrap/wrap-ostream.hpp delete mode 100644 luprex/core/wrap/wrap-utility.hpp diff --git a/luprex/core/cpp/animqueue.hpp b/luprex/core/cpp/animqueue.hpp index 593e5869..d41499b4 100644 --- a/luprex/core/cpp/animqueue.hpp +++ b/luprex/core/cpp/animqueue.hpp @@ -49,13 +49,13 @@ #include "wrap-string.hpp" #include "wrap-deque.hpp" #include "wrap-unordered-map.hpp" -#include "wrap-ostream.hpp" #include "streambuffer.hpp" #include "debugcollector.hpp" #include "util.hpp" #include +#include class AnimStep { friend class AnimQueue; diff --git a/luprex/core/cpp/debugcollector.cpp b/luprex/core/cpp/debugcollector.cpp index 4d482612..95404a23 100644 --- a/luprex/core/cpp/debugcollector.cpp +++ b/luprex/core/cpp/debugcollector.cpp @@ -1,7 +1,7 @@ -#include "wrap-algorithm.hpp" #include +#include #include "debugcollector.hpp" #include "util.hpp" @@ -56,7 +56,7 @@ bool DebugCollector::do_header() { return true; } -void DebugCollector::dump(eng::ostream &os) { +void DebugCollector::dump(std::ostream &os) { flush(); for (const eng::string &line : lines_) { os << line << std::endl; diff --git a/luprex/core/cpp/debugcollector.hpp b/luprex/core/cpp/debugcollector.hpp index 8768b427..8376e394 100644 --- a/luprex/core/cpp/debugcollector.hpp +++ b/luprex/core/cpp/debugcollector.hpp @@ -3,9 +3,10 @@ #include "wrap-vector.hpp" #include "wrap-string.hpp" -#include "wrap-memory.hpp" #include "wrap-sstream.hpp" -#include "wrap-ostream.hpp" + +#include +#include class DebugCollector { private: @@ -28,7 +29,7 @@ public: DebugCollector(const eng::string &targets); bool do_header(); bool do_line(); - void dump(eng::ostream &os); + void dump(std::ostream &os); friend class DebugBlock; }; diff --git a/luprex/core/cpp/drivenengine.cpp b/luprex/core/cpp/drivenengine.cpp index 7a90add6..f78389fb 100644 --- a/luprex/core/cpp/drivenengine.cpp +++ b/luprex/core/cpp/drivenengine.cpp @@ -1,30 +1,32 @@ #include "wrap-string.hpp" #include "wrap-vector.hpp" -#include "wrap-utility.hpp" +#include #include #include #include "drivenengine.hpp" -static eng::vector> makers; +DrivenEngineReg *DrivenEngineReg::All; -void DrivenEngine::register_maker(const char *kind, DrivenEngineMaker maker) { - eng::string skind(kind); - makers.push_back(std::make_pair(skind, maker)); +DrivenEngineReg::DrivenEngineReg(const char *n, DrivenEngineMaker fn) { + name = n; + maker = fn; + next = All; + All = this; } -void DrivenEngine::print_usage(eng::ostream &strm, const char *progname) { +void DrivenEngine::print_usage(std::ostream &strm, const char *progname) { strm << "Usage: " << progname << " " << std::endl; - for (const auto &mpair : makers) { - strm << " Mode can be: " << mpair.first << std::endl; + for (auto reg = DrivenEngineReg::All; reg != nullptr; reg=reg->next) { + strm << " Mode can be: " << reg->name << std::endl; } } UniqueDrivenEngine DrivenEngine::make(const char *kind) { - for (const auto &mpair : makers) { - if (strcmp(mpair.first.c_str(), kind) == 0) { - return mpair.second(); + for (auto reg = DrivenEngineReg::All; reg != nullptr; reg=reg->next) { + if (strcmp(reg->name, kind) == 0) { + return reg->maker(); } } return nullptr; @@ -38,8 +40,8 @@ Channel::Channel(DrivenEngine *de, int chid, int port, const eng::string &target readline_lastc_ = 0; desired_prompt_ = ""; stop_driver_ = stop; - sb_in_ = std::make_shared(); - sb_out_ = std::make_shared(); + sb_in_ = eng::make_shared(); + sb_out_ = eng::make_shared(); sb_drvout_ = sb_out_; } @@ -160,7 +162,7 @@ double DrivenEngine::get_clock() { SharedChannel DrivenEngine::new_outgoing_channel(const eng::string &target) { int chid = find_unused_chid(); new_outgoing_.push_back(chid); - SharedChannel result = std::make_shared(this, chid, 0, target, stop_driver_); + SharedChannel result = eng::make_shared(this, chid, 0, target, stop_driver_); channels_[chid] = result; return result; } @@ -250,7 +252,7 @@ void DrivenEngine::drv_notify_close(int chid, std::string_view err) { int DrivenEngine::drv_notify_accept(int port) { int chid = find_unused_chid(); - channels_[chid] = std::make_shared(this, chid, port, "", stop_driver_); + channels_[chid] = eng::make_shared(this, chid, port, "", stop_driver_); accepted_channels_.push_back(channels_[chid]); return chid; } @@ -288,8 +290,8 @@ bool DrivenEngine::drv_get_stop_driver() const { DrivenEngine::DrivenEngine() { next_unused_chid_ = 1; - stdio_channel_ = std::make_shared(this, 0, 0, "", false); - stdio_channel_->sb_drvout_ = std::make_shared(); + stdio_channel_ = eng::make_shared(this, 0, 0, "", false); + stdio_channel_->sb_drvout_ = eng::make_shared(); channels_[0] = stdio_channel_; rescan_lua_source_ = true; clock_ = 0.0; diff --git a/luprex/core/cpp/drivenengine.hpp b/luprex/core/cpp/drivenengine.hpp index a0a8ff47..d86ef3f1 100644 --- a/luprex/core/cpp/drivenengine.hpp +++ b/luprex/core/cpp/drivenengine.hpp @@ -92,16 +92,18 @@ #ifndef DRIVENENGINE_HPP #define DRIVENENGINE_HPP -#include "wrap-memory.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" -#include "wrap-ostream.hpp" + +#include +#include +#include #include "util.hpp" #include "streambuffer.hpp" class DrivenEngine; -using UniqueDrivenEngine = eng::unique_ptr; +using UniqueDrivenEngine = std::unique_ptr; using DrivenEngineMaker = UniqueDrivenEngine (*)(); class Channel { @@ -162,13 +164,13 @@ private: int chid_; // These are the in/out buffers presented to the user. - eng::shared_ptr sb_in_; - eng::shared_ptr sb_out_; + std::shared_ptr sb_in_; + std::shared_ptr sb_out_; // If this is stdio, we inject tty echoes into the output stream. // This buffer holds the users output interleaved with the tty echoes. // In any other channel, this is just another pointer to sb_out. - eng::shared_ptr sb_drvout_; + std::shared_ptr sb_drvout_; int port_; bool closed_; @@ -186,10 +188,20 @@ private: friend class DrivenEngine; }; -using SharedChannel = eng::shared_ptr; +using SharedChannel = std::shared_ptr; class DrivenEngine { public: + ////////////////////////////////////////////////////////////// + // + // Build the named engine + // + ////////////////////////////////////////////////////////////// + + static UniqueDrivenEngine make(const char *name); + + static void print_usage(std::ostream &strm, const char *progname); + ////////////////////////////////////////////////////////////// // // The following methods are the 'engine' side of the pipe. @@ -254,7 +266,7 @@ public: // Obtain the output buffer of the stdio channel as an ostream. // - eng::ostream &stdostream() { return get_stdio_channel()->out()->ostream(); } + std::ostream &stdostream() { return get_stdio_channel()->out()->ostream(); } // Fetches the lua source, and takes ownership of it. The DrivenEngine // no longer contains the source after calling this. @@ -408,19 +420,6 @@ public: static void set(DrivenEngine *de); static DrivenEngine *get(); -public: - ////////////////////////////////////////////////////////////// - // - // The Registry of DrivenEngineMakers. - // - ////////////////////////////////////////////////////////////// - - static void register_maker(const char *kind, DrivenEngineMaker maker); - - static void print_usage(eng::ostream &strm, const char *progname); - - static UniqueDrivenEngine make(const char *kind); - private: // Find a currently-unused channel ID. Channel IDs // are small integers that are reused. @@ -443,4 +442,19 @@ private: friend class Channel; }; +struct DrivenEngineReg { + const char *name; + DrivenEngineMaker maker; + DrivenEngineReg *next; + static DrivenEngineReg *All; + DrivenEngineReg(const char *name, DrivenEngineMaker f); +}; + +#define DrivenEngineDefine(name, cname) \ + UniqueDrivenEngine dengmake_##cname() { \ + return UniqueDrivenEngine(new cname); \ + } \ + DrivenEngineReg dengreg_##cname(name, dengmake_##cname); + + #endif // DRIVENENGINE_HPP diff --git a/luprex/core/cpp/driver-common.cpp b/luprex/core/cpp/driver-common.cpp index fc0fd186..cd15ea03 100644 --- a/luprex/core/cpp/driver-common.cpp +++ b/luprex/core/cpp/driver-common.cpp @@ -2,8 +2,8 @@ #define CHBUF_SIZE (256*1024) #define POLLVEC_SIZE (DrivenEngine::MAX_CHAN+1) -static drv::unique_ptr chbuf; -static drv::unique_ptr pollvec; +static std::unique_ptr chbuf; +static std::unique_ptr pollvec; static MonoClock monoclock; @@ -13,45 +13,33 @@ namespace util { } } -static void initialize_engine() { - SourceDB::register_lua_builtins(); - DrivenEngine::register_maker("textgame", make_TextGame); - DrivenEngine::register_maker("lpxclient", make_LpxClient); - DrivenEngine::register_maker("lpxserver", make_LpxServer); - DrivenEngine::register_maker("driverstubtest", make_DriverStubTest); - DrivenEngine::register_maker("driverwebservertest", make_DriverWebServerTest); - DrivenEngine::register_maker("driverdnsfailtest", make_DriverDNSFailTest); - DrivenEngine::register_maker("driverprintclocktest", make_DriverPrintClockTest); - DrivenEngine::register_maker("unittest", make_RunUnitTests); -} - static void allocate_buffers() { chbuf.reset(new char[CHBUF_SIZE]); pollvec.reset(new struct pollfd[POLLVEC_SIZE]); } -static void if_error_print_and_exit(const drv::string &str) { +static void if_error_print_and_exit(const std::string &str) { if (!str.empty()) { std::cerr << std::endl << "error: " << str << std::endl; exit(1); } } -static std::string_view read_file(const char *fn, char *buf, int bufsize, drv::string &err) { +static std::string_view read_file(const char *fn, char *buf, int bufsize, std::string &err) { FILE *f = fopen(fn, "r"); if (f == 0) { - err = drv::string("cannot read file") + fn; + err = std::string("cannot read file") + fn; buf[0] = 0; return std::string_view(buf, 0); } int nread = fread(buf, 1, bufsize, f); if (nread < 0) { - err = drv::string("cannot read file: ") + fn; + err = std::string("cannot read file: ") + fn; buf[0] = 0; return std::string_view(buf, 0); } if (nread == bufsize) { - err = drv::string("file too large: ") + fn; + err = std::string("file too large: ") + fn; buf[0] = 0; return std::string_view(buf, 0); } @@ -74,12 +62,12 @@ static SSL_CTX *new_ssl_context(bool server_cert, bool root_certs, std::string_v return ctx; } -static drv::string err_print_errors_str() { +static std::string err_print_errors_str() { BIO *bio = BIO_new(BIO_s_mem()); ERR_print_errors(bio); char *buf; size_t len = BIO_get_mem_data(bio, &buf); - drv::string ret(buf, len); + std::string ret(buf, len); BIO_free(bio); return ret; } @@ -133,8 +121,8 @@ public: }; DrivenEngine *driven_; - drv::vector chans_; - drv::map listen_sockets_; + std::vector chans_; + std::map listen_sockets_; bool read_console_recently_; SSL_CTX *ssl_ctx_with_root_certs_; @@ -146,7 +134,7 @@ public: const auto &listenports = driven_->drv_get_listen_ports(); for (int port : listenports) { if (listen_sockets_.find(port) == listen_sockets_.end()) { - drv::string err; + std::string err; SOCKET sock = listen_on_port(port, err); if_error_print_and_exit(err); assert(sock != INVALID_SOCKET); @@ -157,13 +145,13 @@ public: void handle_lua_source() { if (driven_->drv_get_rescan_lua_source()) { - drv::string err; + std::string err; std::string_view ctrl = read_file("lua/control.lst", chbuf.get(), CHBUF_SIZE, err); if_error_print_and_exit(err); - drv::vector names = drv::parse_control_lst(ctrl); + std::vector names = drv::parse_control_lst(ctrl); driven_->drv_clear_lua_source(); - for (const drv::string &str : names) { - drv::string lfn = drv::string("lua/") + str; + for (const std::string &str : names) { + std::string lfn = std::string("lua/") + str; std::string_view data = read_file(lfn.c_str(), chbuf.get(), CHBUF_SIZE, err); if_error_print_and_exit(err); driven_->drv_add_lua_source(str, data); @@ -255,7 +243,7 @@ public: void handle_new_outgoing_sockets() { const auto &chans = driven_->drv_get_new_outgoing(); for (int chid : chans) { - drv::string err; + std::string err; SOCKET sock = open_connection(driven_->drv_get_target(chid), err); if (sock == INVALID_SOCKET) { driven_->drv_notify_close(chid, err); @@ -270,7 +258,7 @@ public: } void accept_connection(int port, SOCKET sock) { - drv::string err; + std::string err; SOCKET socket = accept_on_socket(sock, err); if_error_print_and_exit(err); if (socket != INVALID_SOCKET) { @@ -281,7 +269,7 @@ public: } void advance_plaintext(ChanInfo &chan) { - drv::string err; + std::string err; // If the channel has no outgoing bytes and has been released, // just close it. @@ -418,7 +406,7 @@ public: void handle_socket_input_output() { - drv::string err; + std::string err; int mstimeout = read_console_recently_ ? 100 : 1000; // Peek output buffers and determine channel release flags. diff --git a/luprex/core/cpp/driver-linux.cpp b/luprex/core/cpp/driver-linux.cpp index 00be1223..268d109b 100644 --- a/luprex/core/cpp/driver-linux.cpp +++ b/luprex/core/cpp/driver-linux.cpp @@ -6,10 +6,6 @@ #include "drivenengine.hpp" #include "dummycert.hpp" #include "util.hpp" -#include "textgame.hpp" -#include "lpxclient.hpp" -#include "lpxserver.hpp" -#include "eng-tests.hpp" #include "source.hpp" #include @@ -43,7 +39,7 @@ const int INVALID_SOCKET = -1; struct termios orig_termios; -static drv::string strerror_str(int err) { +static std::string strerror_str(int err) { char errbuf[256]; return strerror_r(errno, errbuf, 256); } @@ -73,7 +69,7 @@ static void enable_tty_raw() { assert(status >= 0); } -static SOCKET open_connection(std::string_view target, drv::string &err) { +static SOCKET open_connection(std::string_view target, std::string &err) { struct addrinfo *addrs = nullptr; struct addrinfo *goodaddr = nullptr; struct addrinfo hints; @@ -86,7 +82,7 @@ static SOCKET open_connection(std::string_view target, drv::string &err) { hints.ai_flags = AI_NUMERICSERV; err.clear(); - drv::string host, port; + std::string host, port; drv::split_host_port(target, host, port); int status = getaddrinfo(host.c_str(), port.c_str(), &hints, &addrs); if (status != 0) { @@ -119,7 +115,7 @@ error_general: return INVALID_SOCKET; } -static SOCKET listen_on_port(int port, drv::string &err) { +static SOCKET listen_on_port(int port, std::string &err) { int status, enable; err.clear(); @@ -150,7 +146,7 @@ error_errno: return INVALID_SOCKET; } -static SOCKET accept_on_socket(SOCKET listen_socket, drv::string &err) { +static SOCKET accept_on_socket(SOCKET listen_socket, std::string &err) { err.clear(); SOCKET chsock = accept(listen_socket, nullptr, nullptr); if (chsock >= 0) { @@ -170,7 +166,7 @@ static SOCKET accept_on_socket(SOCKET listen_socket, drv::string &err) { // zero: would block // negative: channel closed, possibly cleanly or possibly with error // -static int socket_send(SOCKET socket, const char *bytes, int nbytes, drv::string &err) { +static int socket_send(SOCKET socket, const char *bytes, int nbytes, std::string &err) { err.clear(); int wbytes = send(socket, bytes, nbytes, 0); if (wbytes < 0) { @@ -185,7 +181,7 @@ static int socket_send(SOCKET socket, const char *bytes, int nbytes, drv::string } } -static int socket_recv(SOCKET socket, char *bytes, int nbytes, drv::string &err) { +static int socket_recv(SOCKET socket, char *bytes, int nbytes, std::string &err) { err.clear(); int nrecv = recv(socket, bytes, nbytes, 0); if (nrecv < 0) { @@ -206,7 +202,7 @@ static int socket_close(SOCKET socket) { return close(socket); } -static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, drv::string &err) { +static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, std::string &err) { // socket_poll is implicitly expected to also poll stdin, // if the OS allows that. Linux does, so we add stdin to the // poll vector. The poll vector is required to have at @@ -272,7 +268,7 @@ int main(int argc, char **argv) allocate_buffers(); enable_tty_raw(); OPENSSL_init_ssl(0, NULL); - initialize_engine(); + SourceDB::register_lua_builtins(); driver_drive(argc, argv); } diff --git a/luprex/core/cpp/driver-mingw.cpp b/luprex/core/cpp/driver-mingw.cpp index d9e9d3d7..0da25d99 100644 --- a/luprex/core/cpp/driver-mingw.cpp +++ b/luprex/core/cpp/driver-mingw.cpp @@ -9,10 +9,6 @@ #include "drivenengine.hpp" #include "dummycert.hpp" #include "util.hpp" -#include "textgame.hpp" -#include "lpxclient.hpp" -#include "lpxserver.hpp" -#include "eng-tests.hpp" #include "source.hpp" #include @@ -35,8 +31,8 @@ #define CHBUF_SIZE (256*1024) #define POLLVEC_SIZE (DrivenEngine::MAX_CHAN+1) -static drv::unique_ptr chbuf; -static drv::unique_ptr pollvec; +static std::unique_ptr chbuf; +static std::unique_ptr pollvec; static void set_nonblocking(SOCKET sock) { u_long mode = 1; // 1 to enable non-blocking socket @@ -44,7 +40,7 @@ static void set_nonblocking(SOCKET sock) { assert(status == 0); } -static drv::string winsock_error_string(int errcode) { +static std::string winsock_error_string(int errcode) { drv::ostringstream oss; oss << "error " << errcode; return oss.str(); @@ -55,11 +51,11 @@ static PADDRINFOA find_good_addr(PADDRINFOA addrinfo) { if (addr->ai_family == AF_INET) { return addr; } - }drv::string + }std::string return nullptr; } -static SOCKET open_connection(std::string_view target, drv::string &err) { +static SOCKET open_connection(std::string_view target, std::string &err) { PADDRINFOA addrs = nullptr; PADDRINFOA goodaddr = nullptr; SOCKET sock = INVALID_SOCKET; @@ -107,7 +103,7 @@ error: return SOCKET_ERROR; } -SOCKET listen_on_port(int port, drv::string &err) { +SOCKET listen_on_port(int port, std::string &err) { int status; err.clear(); SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); @@ -140,7 +136,7 @@ error: return SOCKET_ERROR; } -static SOCKET accept_on_socket(SOCKET listen_socket, drv::string &err) { +static SOCKET accept_on_socket(SOCKET listen_socket, std::string &err) { SOCKET chsock = accept(listen_socket, nullptr, nullptr); if (chsock != INVALID_SOCKET) { set_nonblocking(chsock); @@ -156,7 +152,7 @@ static SOCKET accept_on_socket(SOCKET listen_socket, drv::string &err) { } } -static int socket_send(SOCKET socket, const char *bytes, int nbytes, drv::string &err) { +static int socket_send(SOCKET socket, const char *bytes, int nbytes, std::string &err) { err.clear(); int wbytes = send(socket, bytes, nbytes, 0); if (wbytes == SOCKET_ERROR) { @@ -173,7 +169,7 @@ static int socket_send(SOCKET socket, const char *bytes, int nbytes, drv::string } } -static int socket_recv(SOCKET socket, char *bytes, int nbytes, drv::string &err) { +static int socket_recv(SOCKET socket, char *bytes, int nbytes, std::string &err) { err.clear(); int nrecv = recv(socket, bytes, nbytes, 0); if (nrecv < 0) { @@ -195,7 +191,7 @@ static int socket_close(SOCKET socket) { return closesocket(socket); } -static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, drv::string &err) { +static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, std::string &err) { int status = WSAPoll(pollvec, pollcount, mstimeout); if (status < 0) { err = winsock_error_string(WSAGetLastError()); @@ -276,7 +272,7 @@ int main(int argc, char **argv) allocate_buffers(); init_winsock(); OPENSSL_init_ssl(0, NULL); - initialize_engine(); + SourceDB::register_lua_builtins(); driver_drive(argc, argv); } diff --git a/luprex/core/cpp/driver-util.cpp b/luprex/core/cpp/driver-util.cpp index c53a0bb9..8bf3d8fa 100644 --- a/luprex/core/cpp/driver-util.cpp +++ b/luprex/core/cpp/driver-util.cpp @@ -8,10 +8,9 @@ #include "luastack.hpp" #include "util.hpp" - namespace drv { -void split_host_port(std::string_view target, drv::string &host, drv::string &port) { +void split_host_port(std::string_view target, std::string &host, std::string &port) { size_t lastcolon = target.rfind(':'); if (lastcolon == std::string_view::npos) { host = ""; port = ""; return; @@ -23,8 +22,8 @@ void split_host_port(std::string_view target, drv::string &host, drv::string &po } } -drv::vector parse_control_lst(std::string_view ctrl) { - drv::vector result; +std::vector parse_control_lst(std::string_view ctrl) { + std::vector result; while (!ctrl.empty()) { std::string_view line = util::sv_read_line(ctrl); std::string_view trimmed = util::sv_trim(line); @@ -40,7 +39,7 @@ drv::vector parse_control_lst(std::string_view ctrl) { LuaDefine(unittests_driverutil, "", "some unit tests") { // Test split_host_port - drv::string host, port; + std::string host, port; drv::split_host_port("stanford.edu:80", host, port); LuaAssertStrEq(L, host, "stanford.edu"); LuaAssertStrEq(L, port, "80"); diff --git a/luprex/core/cpp/driver-util.hpp b/luprex/core/cpp/driver-util.hpp index 3e27e204..9ff7ec81 100644 --- a/luprex/core/cpp/driver-util.hpp +++ b/luprex/core/cpp/driver-util.hpp @@ -9,9 +9,9 @@ namespace drv { -void split_host_port(std::string_view target, drv::string &host, drv::string &port); +void split_host_port(std::string_view target, std::string &host, std::string &port); -drv::vector parse_control_lst(std::string_view ctrl); +std::vector parse_control_lst(std::string_view ctrl); } diff --git a/luprex/core/cpp/eng-tests.cpp b/luprex/core/cpp/eng-tests.cpp index 04e55e92..a423df4c 100644 --- a/luprex/core/cpp/eng-tests.cpp +++ b/luprex/core/cpp/eng-tests.cpp @@ -1,6 +1,5 @@ #include "wrap-string.hpp" -#include "eng-tests.hpp" #include "drivenengine.hpp" #include "streambuffer.hpp" #include "world.hpp" @@ -122,23 +121,9 @@ private: } }; -UniqueDrivenEngine make_DriverStubTest() { - return UniqueDrivenEngine(new DriverStubTest); -} - -UniqueDrivenEngine make_DriverWebServerTest() { - return UniqueDrivenEngine(new DriverWebServerTest); -} - -UniqueDrivenEngine make_DriverDNSFailTest() { - return UniqueDrivenEngine(new DriverDNSFailTest); -} - -UniqueDrivenEngine make_DriverPrintClockTest() { - return UniqueDrivenEngine(new DriverPrintClockTest); -} - -UniqueDrivenEngine make_RunUnitTests() { - return UniqueDrivenEngine(new RunUnitTests); -} +DrivenEngineDefine("driverstubtest", DriverStubTest); +DrivenEngineDefine("driverwebservertest", DriverWebServerTest); +DrivenEngineDefine("driverdnsfailtest", DriverDNSFailTest); +DrivenEngineDefine("driverprintclocktest", DriverPrintClockTest); +DrivenEngineDefine("rununittests", RunUnitTests); diff --git a/luprex/core/cpp/eng-tests.hpp b/luprex/core/cpp/eng-tests.hpp index bede6fc3..4d1945e5 100644 --- a/luprex/core/cpp/eng-tests.hpp +++ b/luprex/core/cpp/eng-tests.hpp @@ -1,14 +1,5 @@ #ifndef DRIVERTESTS_HPP #define DRIVERTESTS_HPP -#include "drivenengine.hpp" - -UniqueDrivenEngine make_DriverStubTest(); -UniqueDrivenEngine make_DriverListenTest(); -UniqueDrivenEngine make_DriverWebServerTest(); -UniqueDrivenEngine make_DriverDNSFailTest(); -UniqueDrivenEngine make_DriverPrintClockTest(); -UniqueDrivenEngine make_RunUnitTests(); - #endif // DRIVERTESTS_HPP diff --git a/luprex/core/cpp/idalloc.cpp b/luprex/core/cpp/idalloc.cpp index f34f778f..7fb4bd29 100644 --- a/luprex/core/cpp/idalloc.cpp +++ b/luprex/core/cpp/idalloc.cpp @@ -1,10 +1,11 @@ #include "wrap-map.hpp" #include "wrap-sstream.hpp" #include "wrap-deque.hpp" -#include "wrap-ostream.hpp" #include "idalloc.hpp" +#include + static bool ranges_equal(const eng::deque &dq, int64_t a, int64_t b, int64_t c) { if (dq.size() != 3) return false; diff --git a/luprex/core/cpp/idalloc.hpp b/luprex/core/cpp/idalloc.hpp index cf5b425e..2b861e25 100644 --- a/luprex/core/cpp/idalloc.hpp +++ b/luprex/core/cpp/idalloc.hpp @@ -68,13 +68,12 @@ #include "wrap-map.hpp" #include "wrap-sstream.hpp" #include "wrap-deque.hpp" -#include "wrap-ostream.hpp" - #include "luastack.hpp" #include "streambuffer.hpp" #include "debugcollector.hpp" #include +#include class IdGlobalPool { public: diff --git a/luprex/core/cpp/lpxclient.cpp b/luprex/core/cpp/lpxclient.cpp index 377e8c38..4ed6ed89 100644 --- a/luprex/core/cpp/lpxclient.cpp +++ b/luprex/core/cpp/lpxclient.cpp @@ -1,15 +1,15 @@ -#include "wrap-memory.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" #include "drivenengine.hpp" -#include "lpxclient.hpp" #include "world.hpp" #include "luaconsole.hpp" #include "invocation.hpp" #include "util.hpp" #include "printbuffer.hpp" +#include + class LpxClient : public DrivenEngine { public: using StringVec = LuaConsole::StringVec; @@ -282,7 +282,5 @@ public: } }; -UniqueDrivenEngine make_LpxClient() { - return UniqueDrivenEngine(new LpxClient); -} +DrivenEngineDefine("lpxclient", LpxClient); diff --git a/luprex/core/cpp/lpxclient.hpp b/luprex/core/cpp/lpxclient.hpp index b590eb09..a1a2a1a5 100644 --- a/luprex/core/cpp/lpxclient.hpp +++ b/luprex/core/cpp/lpxclient.hpp @@ -1,8 +1,4 @@ #ifndef LPXCLIENT_HPP #define LPXCLIENT_HPP -#include "drivenengine.hpp" - -UniqueDrivenEngine make_LpxClient(); - #endif // LPXCLIENT_HPP diff --git a/luprex/core/cpp/lpxserver.cpp b/luprex/core/cpp/lpxserver.cpp index 46920297..a5a426ac 100644 --- a/luprex/core/cpp/lpxserver.cpp +++ b/luprex/core/cpp/lpxserver.cpp @@ -1,21 +1,21 @@ -#include "wrap-memory.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" -#include "lpxserver.hpp" #include "world.hpp" #include "drivenengine.hpp" #include "luaconsole.hpp" #include "util.hpp" #include "printbuffer.hpp" -class Client { +#include + +class Client : public eng::heap { public: int64_t actor_id_; SharedChannel channel_; UniqueWorld sync_; }; -using UniqueClient = eng::unique_ptr; +using UniqueClient = std::unique_ptr; using ClientVector = eng::vector; class LpxServer : public DrivenEngine { @@ -179,7 +179,5 @@ public: } }; -UniqueDrivenEngine make_LpxServer() { - return UniqueDrivenEngine(new LpxServer); -} +DrivenEngineDefine("lpxserver", LpxServer); diff --git a/luprex/core/cpp/lpxserver.hpp b/luprex/core/cpp/lpxserver.hpp index 2d44460a..e2fbfa32 100644 --- a/luprex/core/cpp/lpxserver.hpp +++ b/luprex/core/cpp/lpxserver.hpp @@ -1,9 +1,5 @@ #ifndef LPXSERVER_HPP #define LPXSERVER_HPP -#include "drivenengine.hpp" - -UniqueDrivenEngine make_LpxServer(); - #endif // LPXSERVER_HPP diff --git a/luprex/core/cpp/luaconsole.cpp b/luprex/core/cpp/luaconsole.cpp index fcab7dd0..a4b44471 100644 --- a/luprex/core/cpp/luaconsole.cpp +++ b/luprex/core/cpp/luaconsole.cpp @@ -1,3 +1,5 @@ +#include "two-mallocs.hpp" +#include "luastack.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" @@ -8,7 +10,7 @@ #include LuaConsole::LuaConsole() { - lua_state_ = luaL_newstate(); + lua_state_ = LuaStack::newstate(lalloc_dlmalloc); clear_raw_input(); } diff --git a/luprex/core/cpp/luasnap.cpp b/luprex/core/cpp/luasnap.cpp index 6f3e91b9..98f3e5f5 100644 --- a/luprex/core/cpp/luasnap.cpp +++ b/luprex/core/cpp/luasnap.cpp @@ -10,7 +10,7 @@ LuaSnap::LuaSnap() { - state_ = luaL_newstate(); + state_ = LuaStack::newstate(lalloc_dlmalloc); LuaStack LS(state_); // Create the persist table and the unpersist table. diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index b19c5222..9a621ac2 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -1,6 +1,7 @@ #include "luastack.hpp" #include #include +#include LuaSpecial LuaRegistry(LUA_REGISTRYINDEX); LuaNilMarker LuaNil; @@ -11,20 +12,12 @@ LuaFunctionReg::LuaFunctionReg(const char *n, const char *a, const char *d, lua_ args_ = a; docs_ = d; func_ = f; - next_ = LuaFunctionRegistry; - LuaFunctionRegistry = this; -} - -LuaFunctionReg::List LuaFunctionReg::all() { - LuaFunctionReg::List result; - for (LuaFunctionReg *r = LuaFunctionRegistry; r != 0; r = r->next_) { - result.push_back(r); - } - return result; + next_ = All; + All = this; } const LuaFunctionReg *LuaFunctionReg::lookup(lua_CFunction fn) { - for (const LuaFunctionReg *r = LuaFunctionRegistry; r != 0; r = r->next_) { + for (const LuaFunctionReg *r = All; r != 0; r = r->next_) { if (r->func_ == fn) { return r; } @@ -32,8 +25,21 @@ const LuaFunctionReg *LuaFunctionReg::lookup(lua_CFunction fn) { return nullptr; } -LuaFunctionReg *LuaFunctionReg::LuaFunctionRegistry; +LuaFunctionReg *LuaFunctionReg::All; +static int panicf(lua_State *L) { + const char *p = lua_tostring(L, -1); + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", p); + fflush(stderr); + exit(1); +} + + +lua_State *LuaStack::newstate (lua_Alloc allocf) { + lua_State *L = lua_newstate(allocf, NULL); + if (L) lua_atpanic(L, &panicf); + return L; +} bool LuaStack::ckboolean(LuaSlot s) const { luaL_checktype(L_, s, LUA_TBOOLEAN); @@ -154,7 +160,7 @@ lua_State *LuaStack::newthread(LuaSlot target) const { return result; } -bool LuaStack::validclassname(const eng::string &cname) { +bool LuaStack::validclassname(std::string_view cname) { if (cname.empty()) return false; if (cname == "_G") return false; return true; @@ -243,15 +249,7 @@ eng::string LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const { } } -eng::string LuaStack::getclass(LuaSlot tab, const char *name) const { - push_any_value(name); - LuaSpecial classname(lua_gettop(L_)); - eng::string err = getclass(tab, classname); - lua_pop(L_, 1); - return err; -} - -eng::string LuaStack::getclass(LuaSlot tab, const eng::string &name) const { +eng::string LuaStack::getclass(LuaSlot tab, std::string_view name) const { push_any_value(name); LuaSpecial classname(lua_gettop(L_)); eng::string err = getclass(tab, classname); @@ -288,14 +286,7 @@ void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const { LS.result(); } -void LuaStack::makeclass(LuaSlot tab, const char *name) const { - push_any_value(name); - LuaSpecial classname(lua_gettop(L_)); - makeclass(tab, classname); - lua_pop(L_, 1); -} - -void LuaStack::makeclass(LuaSlot tab, const eng::string &name) const { +void LuaStack::makeclass(LuaSlot tab, std::string_view name) const { push_any_value(name); LuaSpecial classname(lua_gettop(L_)); makeclass(tab, classname); diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index 38d5dd48..49696f8b 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -155,7 +155,6 @@ #define LUASTACK_HPP #include "wrap-string.hpp" -#include "wrap-vector.hpp" extern "C" { #include "lua.h" @@ -296,6 +295,7 @@ private: void push_any_value(LuaNilMarker s) const { lua_pushnil(L_); } void push_any_value(LuaSlot s) const { lua_pushvalue(L_, s); } void push_any_value(const eng::string &s) const { lua_pushlstring(L_, s.c_str(), s.size()); } + void push_any_value(std::string_view s) const { lua_pushlstring(L_, s.data(), s.size()); } void push_any_value(const char *s) const { lua_pushstring(L_, s); } void push_any_value(float s) const { lua_pushnumber(L_, s); } void push_any_value(double s) const { lua_pushnumber(L_, s); } @@ -334,6 +334,8 @@ public: int result(); public: + static lua_State *newstate (lua_Alloc allocf); + lua_State *state() const { return L_; } int type(LuaSlot s) const { return lua_type(L_, s); } @@ -379,7 +381,7 @@ public: // Return true if the classname is legal. bool validclassname(LuaSlot value) const; - static bool validclassname(const eng::string &cname); + static bool validclassname(std::string_view cname); // Return the class name if x is a valid classtab. // Otherwise, returns empty string. If nonempty, the @@ -392,15 +394,13 @@ public: // There are lots of error conditions, including such things // as no such class, corrupted class, classname invalid, etc. eng::string getclass(LuaSlot tab, LuaSlot name) const; - eng::string getclass(LuaSlot tab, const char *name) const; - eng::string getclass(LuaSlot tab, const eng::string &name) const; + eng::string getclass(LuaSlot tab, std::string_view name) const; // Create a class, or look up an existing class. // WARNING: this routine assert-fails if the parameter is not // a valid classname. Check the classname before calling this! void makeclass(LuaSlot tab, LuaSlot name) const; - void makeclass(LuaSlot tab, const char *name) const; - void makeclass(LuaSlot tab, const eng::string &name) const; + void makeclass(LuaSlot tab, std::string_view name) const; // Get the ID of a tangible. It's a little weird to put this in // this module. @@ -478,19 +478,16 @@ private: lua_CFunction func_; LuaFunctionReg *next_; - static LuaFunctionReg *LuaFunctionRegistry; - public: - using List = eng::vector; - + static LuaFunctionReg *All; LuaFunctionReg(const char *name, const char *args, const char *docs, lua_CFunction f); - static List all(); static const LuaFunctionReg *lookup(lua_CFunction fn); const char *get_name() const { return name_; } const char *get_args() const { return args_; } const char *get_docs() const { return docs_; } lua_CFunction get_func() const { return func_; } + LuaFunctionReg *next() const { return next_; } void set_func(lua_CFunction fn) { func_ = fn; } }; diff --git a/luprex/core/cpp/planemap.cpp b/luprex/core/cpp/planemap.cpp index 8cb45a91..24e74160 100644 --- a/luprex/core/cpp/planemap.cpp +++ b/luprex/core/cpp/planemap.cpp @@ -1,9 +1,9 @@ -#include "wrap-algorithm.hpp" #include "luastack.hpp" #include "util.hpp" #include "planemap.hpp" +#include #include diff --git a/luprex/core/cpp/pprint.cpp b/luprex/core/cpp/pprint.cpp index 33997f8d..850b80a9 100644 --- a/luprex/core/cpp/pprint.cpp +++ b/luprex/core/cpp/pprint.cpp @@ -1,6 +1,5 @@ -#include "wrap-ostream.hpp" - +#include #include "pprint.hpp" #include "util.hpp" #include "table.hpp" @@ -8,7 +7,7 @@ #include -void atomic_print(LuaStack &LS, LuaSlot val, bool quote, eng::ostream *os) { +void atomic_print(LuaStack &LS, LuaSlot val, bool quote, std::ostream *os) { int tt = LS.type(val); switch (tt) { case LUA_TNIL: @@ -103,7 +102,7 @@ struct Inspector { bool indent; int maxlen; bool anyindent; - eng::ostream *stream; + std::ostream *stream; }; static void tabify(Inspector &insp, int level) { @@ -235,7 +234,7 @@ static void pprint_r(Inspector &insp, int level, LuaSlot root) { LS.result(); } -void pprint(LuaStack &LS0, LuaSlot root, bool indent, eng::ostream *os) { +void pprint(LuaStack &LS0, LuaSlot root, bool indent, std::ostream *os) { Inspector insp; LuaStack LS(LS0.state(), insp.ids); findtables(LS, root, insp.ids); diff --git a/luprex/core/cpp/pprint.hpp b/luprex/core/cpp/pprint.hpp index 2b689d13..c39a1a82 100644 --- a/luprex/core/cpp/pprint.hpp +++ b/luprex/core/cpp/pprint.hpp @@ -19,10 +19,8 @@ #ifndef PPRINT_HPP #define PPRINT_HPP -#include "wrap-ostream.hpp" - #include "luastack.hpp" - +#include // Atomic print to a stream. // @@ -30,10 +28,10 @@ // it just prints "". This routine is the heart of the lua // primitives 'print' and 'tostring'. // -void atomic_print(LuaStack &LS, LuaSlot val, bool quote, eng::ostream *os); +void atomic_print(LuaStack &LS, LuaSlot val, bool quote, std::ostream *os); // Pretty print to a stream. // -void pprint(LuaStack &LS, LuaSlot val, bool indent, eng::ostream *os); +void pprint(LuaStack &LS, LuaSlot val, bool indent, std::ostream *os); #endif // PPRINT_HPP \ No newline at end of file diff --git a/luprex/core/cpp/printbuffer.cpp b/luprex/core/cpp/printbuffer.cpp index 90152483..6b231741 100644 --- a/luprex/core/cpp/printbuffer.cpp +++ b/luprex/core/cpp/printbuffer.cpp @@ -1,11 +1,11 @@ -#include "wrap-algorithm.hpp" #include "wrap-sstream.hpp" #include "printbuffer.hpp" +#include #include -struct PrintBufferCore { +struct PrintBufferCore : public eng::heap { // The most recent lines printed. eng::deque lines_; @@ -176,7 +176,7 @@ void PrintBuffer::patch(StreamBuffer *sb, DebugCollector *dbc) { } } -bool PrintChanneler::channel(const PrintBuffer *printbuffer, eng::ostream &ostream) { +bool PrintChanneler::channel(const PrintBuffer *printbuffer, std::ostream &ostream) { if (printbuffer == nullptr) return false; if (printbuffer->first_line() > line_) { line_ = printbuffer->first_line(); diff --git a/luprex/core/cpp/printbuffer.hpp b/luprex/core/cpp/printbuffer.hpp index e06d2248..06858fd6 100644 --- a/luprex/core/cpp/printbuffer.hpp +++ b/luprex/core/cpp/printbuffer.hpp @@ -79,18 +79,17 @@ #include "wrap-deque.hpp" #include "wrap-string.hpp" -#include "wrap-memory.hpp" -#include "wrap-ostream.hpp" - +#include #include "streambuffer.hpp" #include "util.hpp" #include "invocation.hpp" #include "debugcollector.hpp" +#include struct PrintBufferCore; -class PrintBuffer { +class PrintBuffer : public eng::heap { private: PrintBufferCore *core_; @@ -139,7 +138,7 @@ public: }; -class PrintChanneler { +class PrintChanneler : public eng::heap { private: int64_t line_; public: @@ -151,7 +150,7 @@ public: // Copy any new lines from the printbuffer to the stdostream. // Update the current line number. Return true if the printbuffer // contains any lines that have already been channeled. - bool channel(const PrintBuffer *pb, eng::ostream &ostream); + bool channel(const PrintBuffer *pb, std::ostream &ostream); // Generate an invocation that removes unnecessary lines from the // printbuffer. diff --git a/luprex/core/cpp/sched.cpp b/luprex/core/cpp/sched.cpp index c06e845a..dbdaaaf8 100644 --- a/luprex/core/cpp/sched.cpp +++ b/luprex/core/cpp/sched.cpp @@ -1,11 +1,12 @@ #include "wrap-sstream.hpp" -#include "wrap-ostream.hpp" #include "sched.hpp" #include "streambuffer.hpp" #include "luastack.hpp" +#include + bool SchedEntry::operator < (const SchedEntry &other) const { if (clock_ < other.clock_) return true; if (clock_ > other.clock_) return false; diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index bf6d0347..800e3319 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -3,7 +3,6 @@ #include "wrap-vector.hpp" #include "wrap-map.hpp" #include "wrap-set.hpp" -#include "wrap-algorithm.hpp" #include "wrap-sstream.hpp" #include "util.hpp" @@ -13,6 +12,7 @@ #include "source.hpp" #include "luasnap.hpp" +#include #include #include @@ -54,10 +54,10 @@ LuaDefine(classname, "classtable", "get the class name from a class table") { return LS.result(); } -static void get_reg_name(const LuaFunctionReg *reg, eng::string &classname, eng::string &funcname) { - eng::string name = reg->get_name(); +static void get_reg_name(const LuaFunctionReg *reg, std::string_view &classname, std::string_view &funcname) { + std::string_view name(reg->get_name()); size_t upos = name.find('_'); - if (upos == eng::string::npos) { + if (upos == std::string_view::npos) { funcname = name; classname = ""; } else { @@ -337,11 +337,10 @@ static void source_clear_globals(lua_State *L) { static void source_load_cfunctions(lua_State *L) { LuaVar classobj; LuaStack LS(L, classobj); - auto regs = LuaFunctionReg::all(); - for (const LuaFunctionReg *r : regs) { + for (auto r = LuaFunctionReg::All; r != nullptr; r=r->next()) { lua_CFunction func = r->get_func(); - eng::string classname; - eng::string funcname; + std::string_view classname; + std::string_view funcname; get_reg_name(r, classname, funcname); if (classname.empty()) { LS.getglobaltable(classobj); @@ -497,17 +496,17 @@ void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) { } } +// This function should not touch the dlmalloc heap. void SourceDB::register_lua_builtins() { - lua_State *L = luaL_newstate(); + lua_State *L = LuaStack::newstate(lalloc_malloc); luaL_openlibs(L); LuaVar globals,classtab,func; LuaStack LS(L, globals, classtab, func); LS.getglobaltable(globals); - auto regs = LuaFunctionReg::all(); - for (LuaFunctionReg *reg : regs) { + for (auto reg = LuaFunctionReg::All; reg != nullptr; reg=reg->next()) { if (reg->get_func() == nullptr) { - eng::string funcname; - eng::string classname; + std::string_view funcname; + std::string_view classname; get_reg_name(reg, classname, funcname); if (classname.empty()) { LS.rawget(func, globals, funcname); @@ -540,8 +539,8 @@ eng::string SourceDB::function_docs(const LuaStack &LS0, LuaSlot fn) { if (reg == nullptr) { return ""; } - eng::string classname; - eng::string funcname; + std::string_view classname; + std::string_view funcname; get_reg_name(reg, classname, funcname); eng::ostringstream oss; util::StringVec docs = util::split_docstring(reg->get_docs()); diff --git a/luprex/core/cpp/streambuffer.cpp b/luprex/core/cpp/streambuffer.cpp index 865a17d7..d8fdbb20 100644 --- a/luprex/core/cpp/streambuffer.cpp +++ b/luprex/core/cpp/streambuffer.cpp @@ -504,18 +504,18 @@ public: } }; -class StreamBufferOStream : public eng::ostream { +class StreamBufferOStream : public std::ostream { private: StreamBufferWriter writer_; public: - StreamBufferOStream(StreamBuffer *t) : eng::ostream(nullptr), writer_(t) { + StreamBufferOStream(StreamBuffer *t) : std::ostream(nullptr), writer_(t) { rdbuf(&writer_); } virtual ~StreamBufferOStream() { } }; -eng::ostream &StreamBuffer::ostream() { +std::ostream &StreamBuffer::ostream() { if (ostream_ == nullptr) { ostream_.reset(new StreamBufferOStream(this)); } diff --git a/luprex/core/cpp/streambuffer.hpp b/luprex/core/cpp/streambuffer.hpp index a1d8a2e6..0238b5fe 100644 --- a/luprex/core/cpp/streambuffer.hpp +++ b/luprex/core/cpp/streambuffer.hpp @@ -214,14 +214,14 @@ #include "wrap-string.hpp" #include "wrap-sstream.hpp" -#include "wrap-utility.hpp" + +#include +#include +#include #include "luastack.hpp" #include "util.hpp" -#include -#include - class StreamException { public: @@ -404,7 +404,7 @@ public: void *lua_reader_ud(int64_t bytes); // Get an ostream that writes into the StreamBuffer. - eng::ostream &ostream(); + std::ostream &ostream(); private: // Start and end of the allocated block. @@ -429,7 +429,7 @@ private: int64_t lua_reader_size_; // The ostream. Only allocated on demand. - eng::unique_ptr ostream_; + std::unique_ptr ostream_; // Initialize with a new buffer. void init(bool fixed, bool owned, char *buf, int64_t size); diff --git a/luprex/core/cpp/textgame.cpp b/luprex/core/cpp/textgame.cpp index a2b9146d..6223c7c6 100644 --- a/luprex/core/cpp/textgame.cpp +++ b/luprex/core/cpp/textgame.cpp @@ -1,8 +1,6 @@ #include "wrap-vector.hpp" #include "wrap-string.hpp" -#include "wrap-memory.hpp" -#include "wrap-algorithm.hpp" #include "luastack.hpp" #include "util.hpp" @@ -10,11 +8,13 @@ #include "invocation.hpp" #include "world.hpp" #include "traceback.hpp" -#include "textgame.hpp" #include "luaconsole.hpp" #include "pprint.hpp" #include "printbuffer.hpp" +#include "drivenengine.hpp" +#include +#include #include #include #include @@ -131,3 +131,4 @@ private: UniqueDrivenEngine make_TextGame() { return UniqueDrivenEngine(new TextGame); } +static DrivenEngineReg reg_TextGame("textgame", make_TextGame); diff --git a/luprex/core/cpp/two-mallocs.hpp b/luprex/core/cpp/two-mallocs.hpp index c3600993..70c3630a 100644 --- a/luprex/core/cpp/two-mallocs.hpp +++ b/luprex/core/cpp/two-mallocs.hpp @@ -1,9 +1,53 @@ - - +// +// Two Mallocs: +// +// The purpose of this file is to put all engine data structures into +// a private heap that isn't used by any other library. This helps +// achieve determinism when playing a replay log. +// +// For the engine's heap, we chose Doug Lea's Malloc (dlmalloc). It's +// a good general-purpose single-threaded malloc. It's probably not +// the fastest any more (it was, once), but it's still quite good. It +// may be possible to replace dlmalloc with another malloc, but +// dlmalloc is pretty easy to work with. +// +// In order to get all engine data structures into the dlmalloc heap, +// you need to jump through quite a few hoops: +// +// * When using STL classes, you need to use the 'eng' variant of those +// classes: +// +// use 'eng::string' instead of std::string (include "wrap-string.hpp") +// use 'eng::vector' instead of std::vector (include "wrap-vector.hpp") +// use 'eng::map' instead of std::map (include "wrap-map.hpp") +// etc. +// +// These eng classes allocate memory from dlmalloc instead of malloc. +// +// * All your classes must derive from eng::heap. This adds a custom +// operator new and operator delete to your class. +// +// * Use eng::make_shared and eng::make_unique instead of std::make_shared +// and std::make_unique. +// +// * Simple classes like std::pair, std::string_view, std::less, +// std::hash, and so forth don't allocate memory. Those classes +// are not wrapped. There is no eng::pair, eng:less, etc. +// +// * Be aware that most C++ streams use the malloc heap, and there's no +// way to change that. Fortunately, eng::ostringstream uses the +// dlmalloc heap. +// +// * Failing to jump through all these hoops won't break your code in +// any obvious way - you'll just have some of your data structures in +// the malloc heap instead of the dlmalloc heap. This can break +// determinism of replay. +// #ifndef TWO_MALLOCS_HPP #define TWO_MALLOCS_HPP #include +#include // dlmalloc is only used on linux. extern "C" { @@ -21,15 +65,35 @@ void* dlrealloc(void *p, size_t x) { return realloc(p,x); } // Return the current state of the dlmalloc allocator as a 30-bit hash. extern int dlmalloc_hash(); -// EngAllocator: a class meant to be used as an STL Allocator. +// An allocator for lua states that uses dlmalloc and dlfree. +inline void *lalloc_dlmalloc (void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + dlfree(ptr); + return NULL; + } else { + return dlrealloc(ptr, nsize); + } +} + +// An allocator for lua states that uses malloc and free. +inline void *lalloc_malloc (void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, nsize); + } +} + +// eng:allocator: a class meant to be used as an STL Allocator. // Causes objects to be allocated using dlmalloc and dlfree. template -class EngAllocator +class dlmalloc_allocator { public: using value_type = T; - EngAllocator() noexcept {} - template EngAllocator(EngAllocator const&) noexcept {} + dlmalloc_allocator() noexcept {} + template dlmalloc_allocator(dlmalloc_allocator const&) noexcept {} value_type* allocate(std::size_t n) { @@ -43,49 +107,51 @@ public: }; template -bool operator==(EngAllocator const&, EngAllocator const&) noexcept +bool operator==(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept { return true; } - template -bool operator!=(EngAllocator const&, EngAllocator const&) noexcept +bool operator!=(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept { return false; } -// DrvAllocator: a class meant to be used as an STL Allocator. -// Causes objects to be allocated using malloc and free. -template -class DrvAllocator -{ -public: - using value_type = T; - DrvAllocator() noexcept {} - template DrvAllocator(DrvAllocator const&) noexcept {} - - value_type* allocate(std::size_t n) - { - return static_cast(dlmalloc(n*sizeof(value_type))); - } - - void deallocate(value_type* p, std::size_t) noexcept - { - dlfree(p); - } -}; - -template -bool operator==(DrvAllocator const&, DrvAllocator const&) noexcept -{ - return true; +// Another name for dlmalloc_allocator +namespace eng { + template + using allocator = dlmalloc_allocator; } -template -bool operator!=(DrvAllocator const&, DrvAllocator const&) noexcept -{ - return false; -} +// eng::heap a class meant to be used as a base class. +// Causes 'new' and 'delete' for this class to use dlmalloc and dlfree. +namespace eng { + class heap { + public: + void *operator new(size_t size) + { + return dlmalloc(size); + } + + void operator delete(void *p, size_t size) + { + return dlfree(p); + } + }; +} // namespace + +// eng::make_shared allocates shared objects in the dlmalloc heap. +namespace eng { + template + inline std::shared_ptr make_shared(Args&&... args) { + static eng::allocator alloc; + return std::allocate_shared(alloc, args...); + } + template + inline std::unique_ptr make_unique(Args&&... args) { + return std::make_unique(args...); + } +} // namespace eng #endif // TWO_MALLOCS_HPP diff --git a/luprex/core/cpp/util.cpp b/luprex/core/cpp/util.cpp index 5b4e8930..d5728fb9 100644 --- a/luprex/core/cpp/util.cpp +++ b/luprex/core/cpp/util.cpp @@ -1,6 +1,7 @@ #include "wrap-string.hpp" #include "wrap-vector.hpp" -#include "wrap-algorithm.hpp" + +#include #include "util.hpp" @@ -8,7 +9,6 @@ #include #include #include -#include #include #include @@ -41,7 +41,7 @@ bool is_identifier(const eng::string &str) { return true; } -void quote_string(const eng::string &s, eng::ostream *os) { +void quote_string(const eng::string &s, std::ostream *os) { bool anysq = false; bool anydq = false; for (char c : s) { @@ -363,22 +363,22 @@ eng::string XYZ::debug_string() const { } // namespace util -eng::ostream &operator<<(eng::ostream &oss, const util::hex64 &v) { +std::ostream &operator<<(std::ostream &oss, const util::hex64 &v) { oss << "0x" << std::setw(16) << std::setfill('0') << std::hex; return oss; } -eng::ostream &operator<<(eng::ostream &oss, const util::hex32 &v) { +std::ostream &operator<<(std::ostream &oss, const util::hex32 &v) { oss << "0x" << std::setw(8) << std::setfill('0') << std::hex; return oss; } -eng::ostream &operator<<(eng::ostream &oss, const util::hex16 &v) { +std::ostream &operator<<(std::ostream &oss, const util::hex16 &v) { oss << "0x" << std::setw(4) << std::setfill('0') << std::hex; return oss; } -eng::ostream &operator<<(eng::ostream &oss, const util::hex8 &v) { +std::ostream &operator<<(std::ostream &oss, const util::hex8 &v) { oss << "0x" << std::setw(2) << std::setfill('0') << std::hex; return oss; } diff --git a/luprex/core/cpp/util.hpp b/luprex/core/cpp/util.hpp index 8d3f6218..6ea0d13e 100644 --- a/luprex/core/cpp/util.hpp +++ b/luprex/core/cpp/util.hpp @@ -4,12 +4,12 @@ #include "wrap-string.hpp" #include "wrap-set.hpp" #include "wrap-map.hpp" -#include "wrap-algorithm.hpp" +#include "wrap-vector.hpp" #include "wrap-sstream.hpp" -#include "wrap-ostream.hpp" -#include "wrap-memory.hpp" -#include "wrap-utility.hpp" - +#include +#include +#include +#include #include #include "luastack.hpp" @@ -32,11 +32,11 @@ enum MessageType { }; using StringVec = eng::vector; -using StringPair = eng::pair; +using StringPair = std::pair; using StringSet = eng::set; using LuaSourceVec = eng::vector; -using LuaSourcePtr = eng::unique_ptr; -using HashValue = eng::pair; +using LuaSourcePtr = std::unique_ptr; +using HashValue = std::pair; using IdVector = eng::vector; // Return seconds elapsed, for profiling purposes. @@ -46,7 +46,7 @@ double profiling_clock(); bool is_identifier(const eng::string &str); // Output a string to a stream using Lua string escaping and quoting. -void quote_string(const eng::string &str, eng::ostream *os); +void quote_string(const eng::string &str, std::ostream *os); // ID vector quick create. IdVector id_vector_create(int64_t id1=-1, int64_t id2=-1, int64_t id3=-1, int64_t id4=-1); @@ -128,8 +128,8 @@ bool is_lua_comment(const eng::string &line); // Remove nullptrs from a vector of unique pointers. template -void remove_nullptrs(eng::vector> &vec) { - eng::unique_ptr nullp; +void remove_nullptrs(eng::vector> &vec) { + std::unique_ptr nullp; auto iter = std::remove(vec.begin(), vec.end(), nullp); vec.erase(iter, vec.end()); } @@ -144,7 +144,7 @@ struct XYZ { eng::string debug_string() const; }; -// These are formatting directives that can be sent to a eng::ostream. +// These are formatting directives that can be sent to a std::ostream. class hex64 {}; class hex32 {}; class hex16 {}; @@ -158,9 +158,9 @@ public: } // namespace util -eng::ostream &operator<<(eng::ostream &oss, const util::hex64 &v); -eng::ostream &operator<<(eng::ostream &oss, const util::hex32 &v); -eng::ostream &operator<<(eng::ostream &oss, const util::hex16 &v); -eng::ostream &operator<<(eng::ostream &oss, const util::hex8 &v); +std::ostream &operator<<(std::ostream &oss, const util::hex64 &v); +std::ostream &operator<<(std::ostream &oss, const util::hex32 &v); +std::ostream &operator<<(std::ostream &oss, const util::hex16 &v); +std::ostream &operator<<(std::ostream &oss, const util::hex8 &v); #endif // UTIL_HPP diff --git a/luprex/core/cpp/world-accessor.cpp b/luprex/core/cpp/world-accessor.cpp index 217db425..878f1137 100644 --- a/luprex/core/cpp/world-accessor.cpp +++ b/luprex/core/cpp/world-accessor.cpp @@ -314,7 +314,7 @@ LuaDefine(tangible_nopredict, "", LuaDefine(pprint, "obj1,obj2,...", "|Pretty-print object or objects.") { World *w = World::fetch_global_pointer(L); - eng::ostream *ostream = w->lthread_print_stream(); + std::ostream *ostream = w->lthread_print_stream(); LuaStack LS(L); for (int i = 1; i <= lua_gettop(L); i++) { LuaSpecial root(i); @@ -327,7 +327,7 @@ LuaDefine(pprint, "obj1,obj2,...", LuaDefine(print, "obj1,obj2,...", "|Print object or objects.") { World *w = World::fetch_global_pointer(L); - eng::ostream *ostream = w->lthread_print_stream(); + std::ostream *ostream = w->lthread_print_stream(); LuaStack LS(L); int n = lua_gettop(L); for (int i = 1; i <= n; i++) { @@ -342,7 +342,7 @@ LuaDefine(print, "obj1,obj2,...", LuaDefine(doc, "function", "|Print documentation for specified function.") { World *w = World::fetch_global_pointer(L); - eng::ostream *ostream = w->lthread_print_stream(); + std::ostream *ostream = w->lthread_print_stream(); LuaArg func; LuaStack LS(L, func); eng::string doc = SourceDB::function_docs(LS, func); diff --git a/luprex/core/cpp/world-core.cpp b/luprex/core/cpp/world-core.cpp index c1e5d4ab..ac1e89f6 100644 --- a/luprex/core/cpp/world-core.cpp +++ b/luprex/core/cpp/world-core.cpp @@ -294,7 +294,7 @@ eng::string World::probe_lua(int64_t actor_id, const eng::string &lua) { // If there's an error message, print it. // Otherwise, pretty-print the results. - eng::ostream *ostream = lthread_print_stream(); + std::ostream *ostream = lthread_print_stream(); if (status == LUA_OK) { for (int i = top + 1; i <= lua_gettop(L); i++) { LuaSpecial root(i); @@ -683,7 +683,7 @@ void World::run_scheduled_threads() { lua_State *CO = LS.ckthread(thread); open_lthread_state(LS.ckinteger(actorid), sched.place_id(), LS.ckboolean(useppool), true); int status = lua_resume(CO, nullptr, LS.ckint(nargs)); - eng::ostream *ostream = lthread_print_stream(); + std::ostream *ostream = lthread_print_stream(); // Three possible outcomes: finished, yielded, or errored. if (!util::world_type_authoritative(world_type_)) { @@ -786,7 +786,7 @@ void World::close_lthread_state() { clear_lthread_state(); } -eng::ostream *World::lthread_print_stream() const { +std::ostream *World::lthread_print_stream() const { if (lthread_prints_ != nullptr) { return lthread_prints_.get(); } else { diff --git a/luprex/core/cpp/world-testing.cpp b/luprex/core/cpp/world-testing.cpp index 785d6d65..7e99c2c3 100644 --- a/luprex/core/cpp/world-testing.cpp +++ b/luprex/core/cpp/world-testing.cpp @@ -101,7 +101,7 @@ eng::string World::paired_tables_debug_string(lua_State *master) const { LuaVar mntmap, sntmap, mtab, stab, mtid, stid; LuaStack MLS(master, mntmap, mtab, mtid); LuaStack SLS(synch, sntmap, stab, stid); - eng::vector> result; + eng::vector> result; eng::ostringstream oss; // Fetch the numbered tables map. diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index c084f495..75c9b622 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -3,11 +3,12 @@ #define WORLD_HPP #include "wrap-set.hpp" -#include "wrap-utility.hpp" -#include "wrap-memory.hpp" #include "wrap-unordered-map.hpp" #include "wrap-map.hpp" +#include +#include + #include "luastack.hpp" #include "planemap.hpp" #include "idalloc.hpp" @@ -87,7 +88,7 @@ public: void configure_id_pool_for_actor() { id_player_pool_.set_fifo_capacity(3); id_player_pool_.refill(); } }; -using UniqueTangible = eng::unique_ptr; +using UniqueTangible = std::unique_ptr; class World { public: @@ -247,7 +248,7 @@ public: void open_lthread_state(int64_t actor_id, int64_t place_id, bool ppool, bool prints); void close_lthread_state(); - eng::ostream *lthread_print_stream() const; + std::ostream *lthread_print_stream() const; // Allocate a single ID. // @@ -489,7 +490,7 @@ private: int64_t lthread_actor_id_; int64_t lthread_place_id_; int64_t lthread_use_ppool_; - eng::unique_ptr lthread_prints_; + std::unique_ptr lthread_prints_; friend class Tangible; friend int lfn_tangible_animate(lua_State *L); @@ -502,7 +503,7 @@ private: friend int lfn_tangible_scan(lua_State *L); }; -using UniqueWorld = eng::unique_ptr; +using UniqueWorld = std::unique_ptr; #endif // WORLD_HPP diff --git a/luprex/core/wrap/mkstub.py b/luprex/core/wrap/mkstub.py index fd40bdba..df2c64eb 100755 --- a/luprex/core/wrap/mkstub.py +++ b/luprex/core/wrap/mkstub.py @@ -16,7 +16,4 @@ with open(f"wrap-{dash}.hpp", "w") as f: print("namespace eng {", file=f) print("} // namespace eng", file=f) print("", file=f) - print("namespace drv {", file=f) - print("} // namespace drv", file=f) - print("", file=f) print(f"#endif // WRAP_{ubase}_HPP", file=f) diff --git a/luprex/core/wrap/wrap-algorithm.hpp b/luprex/core/wrap/wrap-algorithm.hpp deleted file mode 100644 index 68809345..00000000 --- a/luprex/core/wrap/wrap-algorithm.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef WRAP_ALGORITHM_HPP -#define WRAP_ALGORITHM_HPP - -#include "two-mallocs.hpp" -#include - -namespace eng { -} // namespace eng - -namespace drv { -} // namespace drv - -#endif // WRAP_ALGORITHM_HPP diff --git a/luprex/core/wrap/wrap-deque.hpp b/luprex/core/wrap/wrap-deque.hpp index e5ea7ef1..9e6fc9e7 100644 --- a/luprex/core/wrap/wrap-deque.hpp +++ b/luprex/core/wrap/wrap-deque.hpp @@ -6,12 +6,7 @@ namespace eng { template -using deque = std::deque>; +using deque = std::deque>; } // namespace eng -namespace drv { -template -using deque = std::deque>; -} // namespace drv - #endif // WRAP_DEQUE_HPP diff --git a/luprex/core/wrap/wrap-map.hpp b/luprex/core/wrap/wrap-map.hpp index 217e2bcd..3d017e95 100644 --- a/luprex/core/wrap/wrap-map.hpp +++ b/luprex/core/wrap/wrap-map.hpp @@ -5,21 +5,8 @@ #include namespace eng { -template -using less = std::less; -template -using pair = std::pair; template> -using map = std::map>>; +using map = std::map>>; } // namespace eng -namespace drv { -template -using less = std::less; -template -using pair = std::pair; -template> -using map = std::map>>; -} // namespace drv - #endif // WRAP_MAP_HPP diff --git a/luprex/core/wrap/wrap-memory.hpp b/luprex/core/wrap/wrap-memory.hpp deleted file mode 100644 index cddfddb1..00000000 --- a/luprex/core/wrap/wrap-memory.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef WRAP_MEMORY_HPP -#define WRAP_MEMORY_HPP - -#include "two-mallocs.hpp" -#include - -namespace eng { -template> -using unique_ptr = std::unique_ptr; -template -using shared_ptr = std::shared_ptr; -} // namespace eng - -namespace drv { -template> -using unique_ptr = std::unique_ptr; -template -using shared_ptr = std::shared_ptr; -} // namespace drv - -#endif // WRAP_MEMORY_HPP diff --git a/luprex/core/wrap/wrap-ostream.hpp b/luprex/core/wrap/wrap-ostream.hpp deleted file mode 100644 index 03c1b2bf..00000000 --- a/luprex/core/wrap/wrap-ostream.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef WRAP_OSTREAM_HPP -#define WRAP_OSTREAM_HPP - -#include "two-mallocs.hpp" -#include - -namespace eng { -using ostream = std::ostream; -} // namespace eng - -namespace drv { -using ostream = std::ostream; -} // namespace drv - -#endif // WRAP_OSTREAM_HPP diff --git a/luprex/core/wrap/wrap-set.hpp b/luprex/core/wrap/wrap-set.hpp index 8f4cf4bd..adde1cb4 100644 --- a/luprex/core/wrap/wrap-set.hpp +++ b/luprex/core/wrap/wrap-set.hpp @@ -5,17 +5,8 @@ #include namespace eng { -template -using less = std::less; template> -using set = std::set>; +using set = std::set>; } // namespace eng -namespace drv { -template -using less = std::less; -template> -using set = std::set>; -} // namespace drv - #endif // WRAP_SET_HPP diff --git a/luprex/core/wrap/wrap-sstream.hpp b/luprex/core/wrap/wrap-sstream.hpp index d0fa6a1d..f733ec4d 100644 --- a/luprex/core/wrap/wrap-sstream.hpp +++ b/luprex/core/wrap/wrap-sstream.hpp @@ -6,14 +6,8 @@ namespace eng { template> -using basic_ostringstream = std::basic_ostringstream>; +using basic_ostringstream = std::basic_ostringstream>; using ostringstream = basic_ostringstream; } // namespace eng -namespace drv { -template> -using basic_ostringstream = std::basic_ostringstream>; -using ostringstream = basic_ostringstream; -} // namespace drv - #endif // WRAP_SSTREAM_HPP diff --git a/luprex/core/wrap/wrap-string.hpp b/luprex/core/wrap/wrap-string.hpp index 2f39b78c..2819b752 100644 --- a/luprex/core/wrap/wrap-string.hpp +++ b/luprex/core/wrap/wrap-string.hpp @@ -6,14 +6,8 @@ namespace eng { template> -using basic_string = std::basic_string>; +using basic_string = std::basic_string>; using string = basic_string; } // namespace eng -namespace drv { -template> -using basic_string = std::basic_string>; -using string = basic_string; -} // namespace drv - #endif // WRAP_STRING_HPP diff --git a/luprex/core/wrap/wrap-unordered-map.hpp b/luprex/core/wrap/wrap-unordered-map.hpp index 52468db9..f9edc5ff 100644 --- a/luprex/core/wrap/wrap-unordered-map.hpp +++ b/luprex/core/wrap/wrap-unordered-map.hpp @@ -5,25 +5,8 @@ #include namespace eng { -template -using hash = std::hash; -template -using equal_to = std::equal_to; -template -using pair = std::pair; template, class E=std::equal_to> -using unordered_map = std::unordered_map>>; +using unordered_map = std::unordered_map>>; } // namespace eng -namespace drv { -template -using hash = std::hash; -template -using equal_to = std::equal_to; -template -using pair = std::pair; -template, class E=std::equal_to> -using unordered_map = std::unordered_map>>; -} // namespace drv - #endif // WRAP_UNORDERED_MAP_HPP diff --git a/luprex/core/wrap/wrap-unordered-set.hpp b/luprex/core/wrap/wrap-unordered-set.hpp index f0a7b983..58e3d88e 100644 --- a/luprex/core/wrap/wrap-unordered-set.hpp +++ b/luprex/core/wrap/wrap-unordered-set.hpp @@ -5,21 +5,8 @@ #include namespace eng { -template -using hash = std::hash; -template -using equal_to = std::equal_to; template, class E=std::equal_to> -using unordered_set = std::unordered_set>; +using unordered_set = std::unordered_set>; } // namespace eng -namespace drv { -template -using hash = std::hash; -template -using equal_to = std::equal_to; -template, class E=std::equal_to> -using unordered_set = std::unordered_set>; -} // namespace drv - #endif // WRAP_UNORDERED_SET_HPP diff --git a/luprex/core/wrap/wrap-utility.hpp b/luprex/core/wrap/wrap-utility.hpp deleted file mode 100644 index da986561..00000000 --- a/luprex/core/wrap/wrap-utility.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef WRAP_UTILITY_HPP -#define WRAP_UTILITY_HPP - -#include "two-mallocs.hpp" -#include - -namespace eng { -template -using pair = std::pair; -template< class T1, class T2 > -constexpr std::pair make_pair( T1&& t, T2&& u ) { return std::make_pair(t,u); } -} // namespace eng - -namespace drv { -template -using pair = std::pair; -template< class T1, class T2 > -constexpr std::pair make_pair( T1&& t, T2&& u ) { return std::make_pair(t,u); } -} // namespace drv - -#endif // WRAP_UTILITY_HPP diff --git a/luprex/core/wrap/wrap-vector.hpp b/luprex/core/wrap/wrap-vector.hpp index b53e29ca..077b1790 100644 --- a/luprex/core/wrap/wrap-vector.hpp +++ b/luprex/core/wrap/wrap-vector.hpp @@ -6,12 +6,7 @@ namespace eng { template -using vector = std::vector>; +using vector = std::vector>; } // namespace eng -namespace drv { -template -using vector = std::vector>; -} // namespace drv - #endif // WRAP_VECTOR_HPP From 7cd8eb0a43351b853430214e79b564403fa97b65 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 28 Feb 2022 21:57:54 -0500 Subject: [PATCH 2/3] Lots more work on eng::malloc --- luprex/core/Makefile | 2 +- luprex/core/cpp/driver-linux.cpp | 1 - luprex/core/cpp/eng-malloc.cpp | 122 ++++++++++++++++++ luprex/core/cpp/eng-malloc.hpp | 152 +++++++++++++++++++++++ luprex/core/cpp/eng-tests.cpp | 2 +- luprex/core/cpp/lpxserver.cpp | 2 +- luprex/core/cpp/luaconsole.cpp | 4 +- luprex/core/cpp/luasnap.cpp | 2 +- luprex/core/cpp/luastack.cpp | 16 ++- luprex/core/cpp/printbuffer.cpp | 2 +- luprex/core/cpp/printbuffer.hpp | 4 +- luprex/core/cpp/source.cpp | 2 +- luprex/core/cpp/streambuffer.cpp | 12 +- luprex/core/cpp/two-mallocs.cpp | 64 ---------- luprex/core/cpp/two-mallocs.hpp | 157 ------------------------ luprex/core/wrap/mkstub.py | 2 +- luprex/core/wrap/wrap-deque.hpp | 2 +- luprex/core/wrap/wrap-map.hpp | 2 +- luprex/core/wrap/wrap-set.hpp | 2 +- luprex/core/wrap/wrap-sstream.hpp | 2 +- luprex/core/wrap/wrap-string.hpp | 2 +- luprex/core/wrap/wrap-unordered-map.hpp | 2 +- luprex/core/wrap/wrap-unordered-set.hpp | 2 +- luprex/core/wrap/wrap-vector.hpp | 2 +- luprex/linuxlib/dlmalloc/dlmalloc.c | 5 +- 25 files changed, 314 insertions(+), 253 deletions(-) create mode 100644 luprex/core/cpp/eng-malloc.cpp create mode 100644 luprex/core/cpp/eng-malloc.hpp delete mode 100644 luprex/core/cpp/two-mallocs.cpp delete mode 100644 luprex/core/cpp/two-mallocs.hpp diff --git a/luprex/core/Makefile b/luprex/core/Makefile index 1ee9894f..1d8ea952 100644 --- a/luprex/core/Makefile +++ b/luprex/core/Makefile @@ -65,7 +65,7 @@ LUA_OBJ_FILES=\ CORE_OBJ_FILES=\ obj/invocation.o\ obj/spookyv2.o\ - obj/two-mallocs.o\ + obj/eng-malloc.o\ obj/debugcollector.o\ obj/drivenengine.o\ obj/dummycert.o\ diff --git a/luprex/core/cpp/driver-linux.cpp b/luprex/core/cpp/driver-linux.cpp index 268d109b..ccaf479f 100644 --- a/luprex/core/cpp/driver-linux.cpp +++ b/luprex/core/cpp/driver-linux.cpp @@ -263,7 +263,6 @@ public: int main(int argc, char **argv) { - mallopt(M_MMAP_MAX, 0); // Keep malloc in the 'brk' area. disable_randomization(argc, argv); allocate_buffers(); enable_tty_raw(); diff --git a/luprex/core/cpp/eng-malloc.cpp b/luprex/core/cpp/eng-malloc.cpp new file mode 100644 index 00000000..bccc6c38 --- /dev/null +++ b/luprex/core/cpp/eng-malloc.cpp @@ -0,0 +1,122 @@ + +// We only use a custom allocator on linux (for now) +// The allocator we chose is 'dlmalloc' (doug lea's malloc). +// It's a good allocator for single-threaded programs. +// It needs to be configured by setting a bunch of defines. +// +#ifdef __linux__ + +// We need this to define dlmalloc, not malloc. +#define USE_DL_PREFIX 1 + +// We don't need mspaces. +#define ONLY_MSPACES 0 +#define MSPACES 0 + +// We don't need mallinfo +#define NO_MALLINFO 1 + +// We don't need dlmalloc_inspect_all +#define MALLOC_INSPECT_ALL 0 + +// Disable locking. The entire engine is single-threaded. +#define USE_LOCKS 0 + +// This allocator can use sbrk to obtain RAM. We're going to +// emulate sbrk, in order to put it in a different memory region +// than the system malloc, which also uses sbrk. +#define HAVE_MORECORE 1 +#define MORECORE emulated_sbrk +#define MORECORE_CANNOT_TRIM 1 + +// We won't let the memory allocator use mmap. This is because +// opening the replay log may be implemented in stdio using mmap. +// So using mmap might trigger different results under replay. +#define HAVE_MMAP 0 + +// Fix a warning in dlmalloc. +#define MAX_RELEASE_CHECK_RATE INT_MAX + +// Don't generate random seeds, or time-based seeds. +#define USE_DEV_RANDOM 0 +#define LACKS_TIME_H 1 + +// Don't export any dlmalloc functions. +#define DLMALLOC_EXPORT static inline + +#include +#include +#include +#include + +static char *emulated_sbrk_base; +static intptr_t emulated_sbrk_used; +static intptr_t emulated_sbrk_limit; + +// We assume that the increments are already aligned to the system +// page size, because dlmalloc does that for us. +// +// Our emulated sbrk cannot trim the memory size. It can only grow. +// +static void *emulated_sbrk(intptr_t increment) { + if (emulated_sbrk_base == 0) { + emulated_sbrk_limit = intptr_t(64) * 1024 * 1024 * 1024; + void *map = mmap(nullptr, emulated_sbrk_limit, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(map != MAP_FAILED); + assert(map != nullptr); + emulated_sbrk_base = (char *)map; + emulated_sbrk_used = 0; + } + int64_t old_used = emulated_sbrk_used; + int64_t new_used = emulated_sbrk_used + increment; + if (new_used > emulated_sbrk_limit) { + return (void *)(-1); + } + assert(new_used >= old_used); + emulated_sbrk_used = new_used; + if (new_used > old_used) { + int status = mprotect(emulated_sbrk_base + old_used, new_used - old_used, PROT_READ | PROT_WRITE); + assert(status == 0); + } + return emulated_sbrk_base + old_used; +} + +#include "dlmalloc/dlmalloc.c" + +namespace eng { + static uint32_t hash; + void *malloc(size_t size) { + void *result = dlmalloc(size); + hash += uint32_t(uintptr_t(result)) + 0x83748374; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(size) + 0x85893489; + hash += hash << 10; + hash ^= hash >> 6; + return result; + } + void *realloc(void *p, size_t size) { + void *result = dlrealloc(p, size); + hash += uint32_t(uintptr_t(p)) + 0x74741912; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(uintptr_t(result)) + 0x68843823; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(size) + 0x81444120; + hash += hash << 10; + hash ^= hash >> 6; + return result; + } + void free(void *p) { + hash += uint32_t(uintptr_t(p)) + 0x87823448; + dlfree(p); + } + int memhash() { + return hash; + } +} // namespace eng + +#endif // ifdef __linux__ + + diff --git a/luprex/core/cpp/eng-malloc.hpp b/luprex/core/cpp/eng-malloc.hpp new file mode 100644 index 00000000..a622139e --- /dev/null +++ b/luprex/core/cpp/eng-malloc.hpp @@ -0,0 +1,152 @@ +// +// eng-malloc +// +// The engine has its own private eng::malloc which it uses to allocate +// everything. The engine's malloc heap only contains engine data structures. +// This helps achieve determinism when playing a replay log. +// +// The engine's eng::malloc is a thin wrapper around Doug Lea's Malloc, a good +// general-purpose single-threaded malloc. It's probably not the fastest any +// more (it was, once), but it's still quite good. It's also fairly easy +// to work with. +// +// In order to get all engine data structures into the eng::malloc heap, you +// need to jump through quite a few hoops: +// +// * When using STL classes, you need to use the 'eng' variant of those classes: +// +// - eng::string instead of std::string (include "wrap-string.hpp") +// - eng::vector instead of std::vector (include "wrap-vector.hpp") +// - eng::map instead of std::map (include "wrap-map.hpp") +// - etc. +// +// These eng classes allocate memory using eng::malloc instead of malloc. +// +// * All your classes must derive from eng::opnew. This adds a custom operator +// new and operator delete to your class, which allocate using eng::malloc. +// +// * Use eng::make_shared and eng::make_unique instead of std::make_shared and +// std::make_unique. +// +// * Simple classes like std::pair, std::string_view, std::less, std::hash, and +// so forth don't allocate memory. Those classes are not wrapped. There is +// no eng::pair, eng::less, etc. +// +// * Be aware that most C++ streams use the system malloc heap, and there's no +// way to change that. Fortunately, eng::ostringstream uses the dlmalloc +// heap. +// +// * Failing to jump through all these hoops won't break your code in any +// obvious way - you'll just have some of your data structures in the malloc +// heap instead of the eng::malloc heap. This can break determinism of +// replay. +// +#ifndef ENG_MALLOC_HPP +#define ENG_MALLOC_HPP + +#include +#include + +namespace eng { +#ifdef __linux__ +void* malloc(size_t x); +void free(void *p); +void* realloc(void*, size_t); +int memhash(); +#else +inline void *malloc(size_t x) { return ::malloc(x); } +inline void free(void *p) { return ::free(x); } +inline void *realloc(void *p, size_t x) { return ::realloc(p, x); } +inline int memhash() { return 0; } +#endif +} // namespace eng + +// An allocator for lua states that uses eng::malloc and eng::free +namespace eng { + inline void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + ::eng::free(ptr); + return NULL; + } else { + return ::eng::realloc(ptr, nsize); + } + } +} // namespace eng + +// eng_allocator is similar to std::allocator, but allocates +// objects using eng::malloc and eng::free. +template +class eng_allocator +{ +public: + using value_type = T; + eng_allocator() noexcept {} + template eng_allocator(eng_allocator const&) noexcept {} + + value_type* allocate(std::size_t n) + { + return static_cast(eng::malloc(n*sizeof(value_type))); + } + + void deallocate(value_type* p, std::size_t) noexcept + { + eng::free(p); + } +}; + +// Another name for eng_allocator is eng::allocator. +namespace eng { + template + using allocator = ::eng_allocator; +} // namespace eng + +// Mandated equality and inequality operators for eng_allocator. +template +bool operator==(const eng_allocator &, const eng_allocator &) noexcept +{ + return true; +} +template +bool operator!=(const eng_allocator &, const eng_allocator &) noexcept +{ + return false; +} + +// eng::opnew. A class containing operator new and operator delete, +// meant to be used as a base class for inheritance. +namespace eng { + class opnew { + public: + void *operator new(size_t size) + { + return ::eng::malloc(size); + } + + void operator delete(void *p, size_t size) + { + return ::eng::free(p); + } + }; +} // namespace eng + +// eng::make_shared allocates shared objects using eng::malloc. +namespace eng { + template + inline ::std::shared_ptr make_shared(Args&&... args) { + static eng::allocator alloc; + return std::allocate_shared(alloc, args...); + } +} + +// eng::make_unique doesn't do anything different than std::make_unique: +// they both use operator new and delete. You must +// derive from eng::opnew to change operator new and delete. +namespace eng { + template + inline ::std::unique_ptr make_unique(Args&&... args) { + return std::make_unique(args...); + } +} // namespace eng + +#endif // ENG_MALLOC_HPP + diff --git a/luprex/core/cpp/eng-tests.cpp b/luprex/core/cpp/eng-tests.cpp index a423df4c..62a38b94 100644 --- a/luprex/core/cpp/eng-tests.cpp +++ b/luprex/core/cpp/eng-tests.cpp @@ -95,7 +95,7 @@ public: virtual void event_update() { double clock = get_clock(); if (clock > last_clock_ + 0.5) { - int ms = dlmalloc_hash(); + int ms = eng::memhash(); stdostream() << std::fixed << std::setprecision(2) << clock << " " << std::hex << ms << " "; count_++; last_clock_ = clock; diff --git a/luprex/core/cpp/lpxserver.cpp b/luprex/core/cpp/lpxserver.cpp index a5a426ac..0ef4e595 100644 --- a/luprex/core/cpp/lpxserver.cpp +++ b/luprex/core/cpp/lpxserver.cpp @@ -9,7 +9,7 @@ #include -class Client : public eng::heap { +class Client : public eng::opnew { public: int64_t actor_id_; SharedChannel channel_; diff --git a/luprex/core/cpp/luaconsole.cpp b/luprex/core/cpp/luaconsole.cpp index a4b44471..a1638b81 100644 --- a/luprex/core/cpp/luaconsole.cpp +++ b/luprex/core/cpp/luaconsole.cpp @@ -1,4 +1,4 @@ -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include "luastack.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" @@ -10,7 +10,7 @@ #include LuaConsole::LuaConsole() { - lua_state_ = LuaStack::newstate(lalloc_dlmalloc); + lua_state_ = LuaStack::newstate(eng::l_alloc); clear_raw_input(); } diff --git a/luprex/core/cpp/luasnap.cpp b/luprex/core/cpp/luasnap.cpp index 98f3e5f5..beb39d59 100644 --- a/luprex/core/cpp/luasnap.cpp +++ b/luprex/core/cpp/luasnap.cpp @@ -10,7 +10,7 @@ LuaSnap::LuaSnap() { - state_ = LuaStack::newstate(lalloc_dlmalloc); + state_ = LuaStack::newstate(eng::l_alloc); LuaStack LS(state_); // Create the persist table and the unpersist table. diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index 9a621ac2..5a92b279 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -34,11 +34,21 @@ static int panicf(lua_State *L) { exit(1); } +// An allocator for lua states that uses system malloc and system free. +static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, nsize); + } +} lua_State *LuaStack::newstate (lua_Alloc allocf) { - lua_State *L = lua_newstate(allocf, NULL); - if (L) lua_atpanic(L, &panicf); - return L; + if (allocf == nullptr) allocf = l_alloc; + lua_State *L = lua_newstate(allocf, NULL); + if (L) lua_atpanic(L, &panicf); + return L; } bool LuaStack::ckboolean(LuaSlot s) const { diff --git a/luprex/core/cpp/printbuffer.cpp b/luprex/core/cpp/printbuffer.cpp index 6b231741..79422361 100644 --- a/luprex/core/cpp/printbuffer.cpp +++ b/luprex/core/cpp/printbuffer.cpp @@ -5,7 +5,7 @@ #include #include -struct PrintBufferCore : public eng::heap { +struct PrintBufferCore : public eng::opnew { // The most recent lines printed. eng::deque lines_; diff --git a/luprex/core/cpp/printbuffer.hpp b/luprex/core/cpp/printbuffer.hpp index 06858fd6..a98849e2 100644 --- a/luprex/core/cpp/printbuffer.hpp +++ b/luprex/core/cpp/printbuffer.hpp @@ -89,7 +89,7 @@ struct PrintBufferCore; -class PrintBuffer : public eng::heap { +class PrintBuffer : public eng::opnew { private: PrintBufferCore *core_; @@ -138,7 +138,7 @@ public: }; -class PrintChanneler : public eng::heap { +class PrintChanneler : public eng::opnew { private: int64_t line_; public: diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index 800e3319..dcc4c882 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -498,7 +498,7 @@ void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) { // This function should not touch the dlmalloc heap. void SourceDB::register_lua_builtins() { - lua_State *L = LuaStack::newstate(lalloc_malloc); + lua_State *L = LuaStack::newstate(nullptr); luaL_openlibs(L); LuaVar globals,classtab,func; LuaStack LS(L, globals, classtab, func); diff --git a/luprex/core/cpp/streambuffer.cpp b/luprex/core/cpp/streambuffer.cpp index d8fdbb20..bda56942 100644 --- a/luprex/core/cpp/streambuffer.cpp +++ b/luprex/core/cpp/streambuffer.cpp @@ -1,6 +1,6 @@ #include "wrap-string.hpp" -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include "streambuffer.hpp" #include "spookyv2.hpp" @@ -25,7 +25,7 @@ StreamBuffer::StreamBuffer() { StreamBuffer::StreamBuffer(int64_t size, bool fixed) { assert(size >= 0); - init(fixed, true, (char*)dlmalloc(size), size); + init(fixed, true, (char*)eng::malloc(size), size); } StreamBuffer::StreamBuffer(const char *s, int64_t size) { @@ -40,7 +40,7 @@ StreamBuffer::StreamBuffer(const eng::string &src) { } StreamBuffer::~StreamBuffer() { - if (owned_ && (buf_lo_ != 0)) dlfree(buf_lo_); + if (owned_ && (buf_lo_ != 0)) eng::free(buf_lo_); } int64_t StreamBuffer::total_reads() const { @@ -87,9 +87,9 @@ void StreamBuffer::make_space_slow(int64_t bytes) { } else if (existing_size >= desired_size) { if (data_size > 0) memcpy(buf_lo_, read_cursor_, data_size); } else { - char *nbuf = (char *)dlmalloc(desired_size); + char *nbuf = (char *)eng::malloc(desired_size); if (data_size > 0) memcpy(nbuf, read_cursor_, data_size); - if (buf_lo_ != nullptr) dlfree(buf_lo_); + if (buf_lo_ != nullptr) eng::free(buf_lo_); buf_lo_ = nbuf; buf_hi_ = nbuf + desired_size; } @@ -116,7 +116,7 @@ char *StreamBuffer::get_overwrite(int64_t size, int64_t write_count_after) { void StreamBuffer::clear() { assert(owned_); if (!fixed_size_) { - if (buf_lo_ != nullptr) dlfree(buf_lo_); + if (buf_lo_ != nullptr) eng::free(buf_lo_); buf_lo_ = 0; buf_hi_ = 0; } diff --git a/luprex/core/cpp/two-mallocs.cpp b/luprex/core/cpp/two-mallocs.cpp deleted file mode 100644 index 67b88dfb..00000000 --- a/luprex/core/cpp/two-mallocs.cpp +++ /dev/null @@ -1,64 +0,0 @@ - -// We only use a custom allocator on linux (for now) -// The allocator we chose is 'dlmalloc' (doug lea's malloc). -// It's a good allocator for single-threaded programs. -// It needs to be configured by setting a bunch of defines. -// -#ifdef __linux__ - -// We need this to define dlmalloc, not malloc. -#define USE_DL_PREFIX 1 - -// We don't need mspaces. -#define ONLY_MSPACES 0 -#define MSPACES 0 - -// We don't need mallinfo -#define NO_MALLINFO 1 - -// We don't need dlmalloc_inspect_all -#define MALLOC_INSPECT_ALL 0 - -// We don't need dlmalloc_stats. -#define NO_MALLOC_STATS 1 - -// Disable locking. The entire engine is single-threaded. -#define USE_LOCKS 0 - -// For now, we'll let the allocator use mmap to get memory. -// It's not clear if this is going to be deterministic. -#define HAVE_MMAP 1 - -// One way to force determinism would be to emulate sbrk -// using mmap and mremap, always putting the heap at a fixed -// address. For now, we're not doing that, we're just -// using mmap and relying on that being deterministic (we hope). -#define HAVE_MORECORE 0 -#define MORECORE emulate_sbrk - -// The properties of mmap under linux -#define MMAP_CLEARS 1 -#define HAVE_MREMAP 1 - -// Don't generate random seeds, or time-based seeds. -#define USE_DEV_RANDOM 0 -#define LACKS_TIME_H 1 - -#include "dlmalloc/dlmalloc.c" - -#endif - -int dlmalloc_hash() { - void *blocks[15]; - int hash = 0; - for (int i = 0; i < 15; i++) { - void *blk = dlmalloc(1 << i); - blocks[i] = blk; - hash = (hash * 17) + (int)(intptr_t)(blk); - } - for (int i = 0; i < 15; i++) { - dlfree(blocks[i]); - } - return (hash & 0x7FFFFFFF) | (0x40000000); -} - diff --git a/luprex/core/cpp/two-mallocs.hpp b/luprex/core/cpp/two-mallocs.hpp deleted file mode 100644 index 70c3630a..00000000 --- a/luprex/core/cpp/two-mallocs.hpp +++ /dev/null @@ -1,157 +0,0 @@ -// -// Two Mallocs: -// -// The purpose of this file is to put all engine data structures into -// a private heap that isn't used by any other library. This helps -// achieve determinism when playing a replay log. -// -// For the engine's heap, we chose Doug Lea's Malloc (dlmalloc). It's -// a good general-purpose single-threaded malloc. It's probably not -// the fastest any more (it was, once), but it's still quite good. It -// may be possible to replace dlmalloc with another malloc, but -// dlmalloc is pretty easy to work with. -// -// In order to get all engine data structures into the dlmalloc heap, -// you need to jump through quite a few hoops: -// -// * When using STL classes, you need to use the 'eng' variant of those -// classes: -// -// use 'eng::string' instead of std::string (include "wrap-string.hpp") -// use 'eng::vector' instead of std::vector (include "wrap-vector.hpp") -// use 'eng::map' instead of std::map (include "wrap-map.hpp") -// etc. -// -// These eng classes allocate memory from dlmalloc instead of malloc. -// -// * All your classes must derive from eng::heap. This adds a custom -// operator new and operator delete to your class. -// -// * Use eng::make_shared and eng::make_unique instead of std::make_shared -// and std::make_unique. -// -// * Simple classes like std::pair, std::string_view, std::less, -// std::hash, and so forth don't allocate memory. Those classes -// are not wrapped. There is no eng::pair, eng:less, etc. -// -// * Be aware that most C++ streams use the malloc heap, and there's no -// way to change that. Fortunately, eng::ostringstream uses the -// dlmalloc heap. -// -// * Failing to jump through all these hoops won't break your code in -// any obvious way - you'll just have some of your data structures in -// the malloc heap instead of the dlmalloc heap. This can break -// determinism of replay. -// -#ifndef TWO_MALLOCS_HPP -#define TWO_MALLOCS_HPP - -#include -#include - -// dlmalloc is only used on linux. -extern "C" { -#ifdef __linux__ -void* dlmalloc(size_t x); -void dlfree(void *p); -void* dlrealloc(void*, size_t); -#else -void* dlmalloc(size_t x) { return malloc(x); } -void dlfree(void *p) { free(p); } -void* dlrealloc(void *p, size_t x) { return realloc(p,x); } -#endif -} - -// Return the current state of the dlmalloc allocator as a 30-bit hash. -extern int dlmalloc_hash(); - -// An allocator for lua states that uses dlmalloc and dlfree. -inline void *lalloc_dlmalloc (void *ud, void *ptr, size_t osize, size_t nsize) { - if (nsize == 0) { - dlfree(ptr); - return NULL; - } else { - return dlrealloc(ptr, nsize); - } -} - -// An allocator for lua states that uses malloc and free. -inline void *lalloc_malloc (void *ud, void *ptr, size_t osize, size_t nsize) { - if (nsize == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, nsize); - } -} - -// eng:allocator: a class meant to be used as an STL Allocator. -// Causes objects to be allocated using dlmalloc and dlfree. -template -class dlmalloc_allocator -{ -public: - using value_type = T; - dlmalloc_allocator() noexcept {} - template dlmalloc_allocator(dlmalloc_allocator const&) noexcept {} - - value_type* allocate(std::size_t n) - { - return static_cast(dlmalloc(n*sizeof(value_type))); - } - - void deallocate(value_type* p, std::size_t) noexcept - { - dlfree(p); - } -}; - -template -bool operator==(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept -{ - return true; -} -template -bool operator!=(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept -{ - return false; -} - -// Another name for dlmalloc_allocator -namespace eng { - template - using allocator = dlmalloc_allocator; -} - -// eng::heap a class meant to be used as a base class. -// Causes 'new' and 'delete' for this class to use dlmalloc and dlfree. -namespace eng { - class heap { - public: - void *operator new(size_t size) - { - return dlmalloc(size); - } - - void operator delete(void *p, size_t size) - { - return dlfree(p); - } - }; -} // namespace - -// eng::make_shared allocates shared objects in the dlmalloc heap. -namespace eng { - template - inline std::shared_ptr make_shared(Args&&... args) { - static eng::allocator alloc; - return std::allocate_shared(alloc, args...); - } - template - inline std::unique_ptr make_unique(Args&&... args) { - return std::make_unique(args...); - } -} // namespace eng - -#endif // TWO_MALLOCS_HPP - diff --git a/luprex/core/wrap/mkstub.py b/luprex/core/wrap/mkstub.py index df2c64eb..568aa722 100755 --- a/luprex/core/wrap/mkstub.py +++ b/luprex/core/wrap/mkstub.py @@ -10,7 +10,7 @@ with open(f"wrap-{dash}.hpp", "w") as f: print(f"#ifndef WRAP_{ubase}_HPP", file=f) print(f"#define WRAP_{ubase}_HPP", file=f) print("", file=f) - print('#include "two-mallocs.hpp"', file=f) + print('#include "eng-malloc.hpp"', file=f) print(f"#include <{base}>", file=f) print("", file=f) print("namespace eng {", file=f) diff --git a/luprex/core/wrap/wrap-deque.hpp b/luprex/core/wrap/wrap-deque.hpp index 9e6fc9e7..238fc0dd 100644 --- a/luprex/core/wrap/wrap-deque.hpp +++ b/luprex/core/wrap/wrap-deque.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_DEQUE_HPP #define WRAP_DEQUE_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-map.hpp b/luprex/core/wrap/wrap-map.hpp index 3d017e95..10905294 100644 --- a/luprex/core/wrap/wrap-map.hpp +++ b/luprex/core/wrap/wrap-map.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_MAP_HPP #define WRAP_MAP_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-set.hpp b/luprex/core/wrap/wrap-set.hpp index adde1cb4..8beee51d 100644 --- a/luprex/core/wrap/wrap-set.hpp +++ b/luprex/core/wrap/wrap-set.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_SET_HPP #define WRAP_SET_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-sstream.hpp b/luprex/core/wrap/wrap-sstream.hpp index f733ec4d..60ed91b5 100644 --- a/luprex/core/wrap/wrap-sstream.hpp +++ b/luprex/core/wrap/wrap-sstream.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_SSTREAM_HPP #define WRAP_SSTREAM_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-string.hpp b/luprex/core/wrap/wrap-string.hpp index 2819b752..df54cc62 100644 --- a/luprex/core/wrap/wrap-string.hpp +++ b/luprex/core/wrap/wrap-string.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_STRING_HPP #define WRAP_STRING_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-unordered-map.hpp b/luprex/core/wrap/wrap-unordered-map.hpp index f9edc5ff..0a3ecd23 100644 --- a/luprex/core/wrap/wrap-unordered-map.hpp +++ b/luprex/core/wrap/wrap-unordered-map.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_UNORDERED_MAP_HPP #define WRAP_UNORDERED_MAP_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-unordered-set.hpp b/luprex/core/wrap/wrap-unordered-set.hpp index 58e3d88e..8854b006 100644 --- a/luprex/core/wrap/wrap-unordered-set.hpp +++ b/luprex/core/wrap/wrap-unordered-set.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_UNORDERED_SET_HPP #define WRAP_UNORDERED_SET_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-vector.hpp b/luprex/core/wrap/wrap-vector.hpp index 077b1790..a9cb254b 100644 --- a/luprex/core/wrap/wrap-vector.hpp +++ b/luprex/core/wrap/wrap-vector.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_VECTOR_HPP #define WRAP_VECTOR_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/linuxlib/dlmalloc/dlmalloc.c b/luprex/linuxlib/dlmalloc/dlmalloc.c index b7f54b70..4fc64718 100644 --- a/luprex/linuxlib/dlmalloc/dlmalloc.c +++ b/luprex/linuxlib/dlmalloc/dlmalloc.c @@ -4286,10 +4286,9 @@ static int sys_trim(mstate m, size_t pad) { if (HAVE_MMAP && sp->size >= extra && !has_segment_link(m, sp)) { /* can't shrink if pinned */ - size_t newsize = sp->size - extra; /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || - (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + if ((CALL_MREMAP(sp->base, sp->size, (sp->size - extra), 0) != MFAIL) || + (CALL_MUNMAP(sp->base + (sp->size - extra), extra) == 0)) { released = extra; } } From cf102a625021bad8241d9ad2ff7ef3fa149d8c31 Mon Sep 17 00:00:00 2001 From: jyelon Date: Wed, 2 Mar 2022 14:52:51 -0500 Subject: [PATCH 3/3] Yet more work on eng::malloc --- luprex/core/badmem.sh | 2 - luprex/core/cpp/animqueue.hpp | 4 +- luprex/core/cpp/debugcollector.hpp | 4 +- luprex/core/cpp/drivenengine.hpp | 4 +- luprex/core/cpp/eng-malloc.hpp | 82 ++++++++++++++++++------- luprex/core/cpp/gui.hpp | 4 +- luprex/core/cpp/idalloc.hpp | 4 +- luprex/core/cpp/invocation.hpp | 2 +- luprex/core/cpp/luaconsole.hpp | 2 +- luprex/core/cpp/luasnap.hpp | 2 +- luprex/core/cpp/luastack.hpp | 6 +- luprex/core/cpp/planemap.hpp | 4 +- luprex/core/cpp/printbuffer.hpp | 4 +- luprex/core/cpp/sched.hpp | 4 +- luprex/core/cpp/source.hpp | 2 +- luprex/core/cpp/streambuffer.cpp | 4 +- luprex/core/cpp/streambuffer.hpp | 4 +- luprex/core/cpp/world.hpp | 4 +- luprex/core/wrap/wrap-deque.hpp | 4 +- luprex/core/wrap/wrap-map.hpp | 4 +- luprex/core/wrap/wrap-set.hpp | 4 +- luprex/core/wrap/wrap-sstream.hpp | 7 ++- luprex/core/wrap/wrap-unordered-map.hpp | 4 +- luprex/core/wrap/wrap-unordered-set.hpp | 4 +- luprex/core/wrap/wrap-vector.hpp | 4 +- 25 files changed, 114 insertions(+), 59 deletions(-) diff --git a/luprex/core/badmem.sh b/luprex/core/badmem.sh index e21ba3d2..10964558 100755 --- a/luprex/core/badmem.sh +++ b/luprex/core/badmem.sh @@ -9,8 +9,6 @@ grep std::unordered_set cpp/* grep std::deque cpp/* grep std::ostringstream cpp/* grep std::ostream cpp/* -grep std::unique_ptr cpp/* -grep std::shared_ptr cpp/* grep std::cerr cpp/* grep std::cout cpp/* diff --git a/luprex/core/cpp/animqueue.hpp b/luprex/core/cpp/animqueue.hpp index d41499b4..03f4420c 100644 --- a/luprex/core/cpp/animqueue.hpp +++ b/luprex/core/cpp/animqueue.hpp @@ -57,7 +57,7 @@ #include #include -class AnimStep { +class AnimStep : public eng::nevernew { friend class AnimQueue; public: enum { @@ -166,7 +166,7 @@ private: }; -class AnimQueue { +class AnimQueue : public eng::nevernew { public: // World type determines whether versions increment or autozero AnimQueue(util::WorldType wt); diff --git a/luprex/core/cpp/debugcollector.hpp b/luprex/core/cpp/debugcollector.hpp index 8376e394..947f90d6 100644 --- a/luprex/core/cpp/debugcollector.hpp +++ b/luprex/core/cpp/debugcollector.hpp @@ -8,7 +8,7 @@ #include #include -class DebugCollector { +class DebugCollector : public eng::nevernew { private: // At any given time, the stringstream may contain one // extra line that hasn't yet been appended to the list of lines. @@ -33,7 +33,7 @@ public: friend class DebugBlock; }; -class DebugBlock { +class DebugBlock : public eng::nevernew { private: DebugCollector *dbc_; int n_regular_; diff --git a/luprex/core/cpp/drivenengine.hpp b/luprex/core/cpp/drivenengine.hpp index d86ef3f1..4cb4d014 100644 --- a/luprex/core/cpp/drivenengine.hpp +++ b/luprex/core/cpp/drivenengine.hpp @@ -106,7 +106,7 @@ class DrivenEngine; using UniqueDrivenEngine = std::unique_ptr; using DrivenEngineMaker = UniqueDrivenEngine (*)(); -class Channel { +class Channel : public eng::opnew { public: // Get the buffers associated with this channel. // @@ -190,7 +190,7 @@ private: using SharedChannel = std::shared_ptr; -class DrivenEngine { +class DrivenEngine : public eng::opnew { public: ////////////////////////////////////////////////////////////// // diff --git a/luprex/core/cpp/eng-malloc.hpp b/luprex/core/cpp/eng-malloc.hpp index a622139e..929e1981 100644 --- a/luprex/core/cpp/eng-malloc.hpp +++ b/luprex/core/cpp/eng-malloc.hpp @@ -13,27 +13,27 @@ // In order to get all engine data structures into the eng::malloc heap, you // need to jump through quite a few hoops: // -// * When using STL classes, you need to use the 'eng' variant of those classes: +// * When writing a class, always derive from eng::opnew. This adds a +// custom operator new to your class, which causes your class to be +// allocated using eng::malloc. // -// - eng::string instead of std::string (include "wrap-string.hpp") -// - eng::vector instead of std::vector (include "wrap-vector.hpp") -// - eng::map instead of std::map (include "wrap-map.hpp") -// - etc. +// * When using STL containers, you need to use the eng variant: +// eng::map, eng::set, eng::vector, eng::unordered_map, eng::unordered_set, +// and eng::deque. These classes derive from eng::opnew, and they also +// use eng::malloc for their internal nodes. // -// These eng classes allocate memory using eng::malloc instead of malloc. -// -// * All your classes must derive from eng::opnew. This adds a custom operator -// new and operator delete to your class, which allocate using eng::malloc. -// -// * Use eng::make_shared and eng::make_unique instead of std::make_shared and -// std::make_unique. +// * Use eng::string instead of std::string. Use eng::ostringstream +// instead of std::ostringstream. // // * Simple classes like std::pair, std::string_view, std::less, std::hash, and -// so forth don't allocate memory. Those classes are not wrapped. There is -// no eng::pair, eng::less, etc. +// so forth are not wrapped. Do not use operator new or delete on +// these classes. +// +// * Instead of std::make_shared, use eng::make_shared. You need this +// because std::make_shared doesn't respect your custom operator new. // // * Be aware that most C++ streams use the system malloc heap, and there's no -// way to change that. Fortunately, eng::ostringstream uses the dlmalloc +// way to change that. Fortunately, eng::ostringstream uses the eng::malloc // heap. // // * Failing to jump through all these hoops won't break your code in any @@ -46,6 +46,7 @@ #include #include +#include namespace eng { #ifdef __linux__ @@ -126,21 +127,60 @@ namespace eng { { return ::eng::free(p); } + + void *operator new[](size_t size) + { + return ::eng::malloc(size); + } + + void operator delete[](void *p, size_t size) + { + return ::eng::free(p); + } }; } // namespace eng +// eng::nevernew. A class containing private operator new and +// operator delete, making it impossible to 'new' the class. +namespace eng { + class nevernew { + private: + void *operator new(size_t size) + { + assert(false && "not supposed to 'new' this class"); + return NULL; + } + + void operator delete(void *p, size_t size) + { + assert(false && "not supposed to 'delete' this class"); + } + + void *operator new[](size_t size) + { + assert(false && "not supposed to 'new' this class"); + return NULL; + } + + void operator delete[](void *p, size_t size) + { + assert(false && "not supposed to 'delete' this class"); + } + }; +} // namespace eng + + // eng::make_shared allocates shared objects using eng::malloc. namespace eng { template inline ::std::shared_ptr make_shared(Args&&... args) { - static eng::allocator alloc; - return std::allocate_shared(alloc, args...); + return std::allocate_shared(eng::allocator(), args...); } -} +} // namespace eng -// eng::make_unique doesn't do anything different than std::make_unique: -// they both use operator new and delete. You must -// derive from eng::opnew to change operator new and delete. +// eng::make_unique doesn't do anything different than std::make_unique: they +// both use operator new and delete. You must derive from eng::opnew to change +// operator new and delete. namespace eng { template inline ::std::unique_ptr make_unique(Args&&... args) { diff --git a/luprex/core/cpp/gui.hpp b/luprex/core/cpp/gui.hpp index 103e50b3..85987321 100644 --- a/luprex/core/cpp/gui.hpp +++ b/luprex/core/cpp/gui.hpp @@ -8,7 +8,7 @@ #include "luastack.hpp" #include "streambuffer.hpp" -class GuiElt { +class GuiElt : public eng::nevernew { friend class Gui; public: enum Type { @@ -27,7 +27,7 @@ public: const eng::string &label() const { return label_; } }; -class Gui { +class Gui : public eng::nevernew { public: using EltVec = eng::vector; private: diff --git a/luprex/core/cpp/idalloc.hpp b/luprex/core/cpp/idalloc.hpp index 2b861e25..ff32a411 100644 --- a/luprex/core/cpp/idalloc.hpp +++ b/luprex/core/cpp/idalloc.hpp @@ -75,7 +75,7 @@ #include #include -class IdGlobalPool { +class IdGlobalPool : public eng::nevernew { public: // Construct and destroy global pools. Note that after constructing // a global pool, it is generally also necessary to initialize it @@ -119,7 +119,7 @@ private: friend int unittests_idalloc(lua_State *L); }; -class IdPlayerPool { +class IdPlayerPool : public eng::nevernew { public: // Construct a player pool. // diff --git a/luprex/core/cpp/invocation.hpp b/luprex/core/cpp/invocation.hpp index 648561fe..49737950 100644 --- a/luprex/core/cpp/invocation.hpp +++ b/luprex/core/cpp/invocation.hpp @@ -16,7 +16,7 @@ public: void deserialize(StreamBuffer *sb); }; -class Invocation { +class Invocation : public eng::nevernew { public: enum Kind { KIND_INVALID, diff --git a/luprex/core/cpp/luaconsole.hpp b/luprex/core/cpp/luaconsole.hpp index e26004bf..5476684f 100644 --- a/luprex/core/cpp/luaconsole.hpp +++ b/luprex/core/cpp/luaconsole.hpp @@ -47,7 +47,7 @@ #include "luastack.hpp" -class LuaConsole { +class LuaConsole : public eng::nevernew { public: using StringVec = eng::vector; diff --git a/luprex/core/cpp/luasnap.hpp b/luprex/core/cpp/luasnap.hpp index 10592f59..0f152ef3 100644 --- a/luprex/core/cpp/luasnap.hpp +++ b/luprex/core/cpp/luasnap.hpp @@ -17,7 +17,7 @@ #include "streambuffer.hpp" #include "luastack.hpp" -class LuaSnap { +class LuaSnap : public eng::nevernew { private: lua_State *state_; diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index 49696f8b..ace53ac3 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -163,7 +163,7 @@ extern "C" { #include "eris.h" } -class LuaSlot { +class LuaSlot : public eng::nevernew { protected: int index_; private: @@ -226,7 +226,7 @@ int LuaTypeTagValue(lua_State *L) { return 0; } #define LUA_TT_GLOBALDB 22 #define LUA_TT_CLASS 23 -class LuaStack { +class LuaStack : public eng::nevernew { private: int narg_; int ngap_; @@ -470,7 +470,7 @@ public: }; -class LuaFunctionReg { +class LuaFunctionReg : public eng::nevernew { private: const char *name_; const char *args_; diff --git a/luprex/core/cpp/planemap.hpp b/luprex/core/cpp/planemap.hpp index 1573e006..bc7a71d6 100644 --- a/luprex/core/cpp/planemap.hpp +++ b/luprex/core/cpp/planemap.hpp @@ -83,7 +83,7 @@ class PlaneMap; -class PlaneItem { +class PlaneItem : public eng::nevernew { friend class PlaneMap; private: @@ -112,7 +112,7 @@ public: void set_xyz(float x, float y, float z) { set_pos(plane_, x, y, z); } }; -class PlaneMap { +class PlaneMap : public eng::nevernew { friend class PlaneItem; private: using EltVec = eng::vector; diff --git a/luprex/core/cpp/printbuffer.hpp b/luprex/core/cpp/printbuffer.hpp index a98849e2..3d98634a 100644 --- a/luprex/core/cpp/printbuffer.hpp +++ b/luprex/core/cpp/printbuffer.hpp @@ -89,7 +89,7 @@ struct PrintBufferCore; -class PrintBuffer : public eng::opnew { +class PrintBuffer : public eng::nevernew { private: PrintBufferCore *core_; @@ -138,7 +138,7 @@ public: }; -class PrintChanneler : public eng::opnew { +class PrintChanneler : public eng::nevernew { private: int64_t line_; public: diff --git a/luprex/core/cpp/sched.hpp b/luprex/core/cpp/sched.hpp index f11aa8a3..9af31c28 100644 --- a/luprex/core/cpp/sched.hpp +++ b/luprex/core/cpp/sched.hpp @@ -7,7 +7,7 @@ #include -class SchedEntry { +class SchedEntry : public eng::nevernew { private: friend class Schedule; int64_t clock_; @@ -30,7 +30,7 @@ public: eng::string debug_string() const; }; -class Schedule { +class Schedule : public eng::nevernew { private: eng::set schedule_; public: diff --git a/luprex/core/cpp/source.hpp b/luprex/core/cpp/source.hpp index 60186ba3..6e1ed175 100644 --- a/luprex/core/cpp/source.hpp +++ b/luprex/core/cpp/source.hpp @@ -127,7 +127,7 @@ #include "streambuffer.hpp" #include "debugcollector.hpp" -class SourceDB { +class SourceDB : public eng::nevernew { private: lua_State *lua_state_; diff --git a/luprex/core/cpp/streambuffer.cpp b/luprex/core/cpp/streambuffer.cpp index bda56942..2019c2d5 100644 --- a/luprex/core/cpp/streambuffer.cpp +++ b/luprex/core/cpp/streambuffer.cpp @@ -490,7 +490,7 @@ void *StreamBuffer::lua_reader_ud(int64_t size) { return this; } -class StreamBufferWriter : public std::streambuf { +class StreamBufferWriter : public std::streambuf, public eng::opnew { private: StreamBuffer *target_; public: @@ -504,7 +504,7 @@ public: } }; -class StreamBufferOStream : public std::ostream { +class StreamBufferOStream : public std::ostream, public eng::opnew { private: StreamBufferWriter writer_; public: diff --git a/luprex/core/cpp/streambuffer.hpp b/luprex/core/cpp/streambuffer.hpp index 0238b5fe..378946ee 100644 --- a/luprex/core/cpp/streambuffer.hpp +++ b/luprex/core/cpp/streambuffer.hpp @@ -222,7 +222,7 @@ #include "luastack.hpp" #include "util.hpp" -class StreamException +class StreamException : public eng::nevernew { public: virtual char const *what() const { return "General stream exception"; } @@ -240,7 +240,7 @@ public: virtual char const *what() const { return "Stream contained invalid data"; } }; -class StreamBuffer { +class StreamBuffer : public eng::nevernew { public: // Construct an empty buffer. StreamBuffer(); diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 75c9b622..2154dbc8 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -24,7 +24,7 @@ class World; -class Tangible { +class Tangible : public eng::opnew { private: friend class World; @@ -90,7 +90,7 @@ public: using UniqueTangible = std::unique_ptr; -class World { +class World : public eng::opnew { public: using IdVector = util::IdVector; using TanVector = eng::vector; diff --git a/luprex/core/wrap/wrap-deque.hpp b/luprex/core/wrap/wrap-deque.hpp index 238fc0dd..6648864e 100644 --- a/luprex/core/wrap/wrap-deque.hpp +++ b/luprex/core/wrap/wrap-deque.hpp @@ -6,7 +6,9 @@ namespace eng { template -using deque = std::deque>; +class deque : public std::deque>, public eng::opnew { + using std::deque>::deque; +}; } // namespace eng #endif // WRAP_DEQUE_HPP diff --git a/luprex/core/wrap/wrap-map.hpp b/luprex/core/wrap/wrap-map.hpp index 10905294..0077eca5 100644 --- a/luprex/core/wrap/wrap-map.hpp +++ b/luprex/core/wrap/wrap-map.hpp @@ -6,7 +6,9 @@ namespace eng { template> -using map = std::map>>; +class map : public std::map>>, eng::opnew { + using std::map>>::map; +}; } // namespace eng #endif // WRAP_MAP_HPP diff --git a/luprex/core/wrap/wrap-set.hpp b/luprex/core/wrap/wrap-set.hpp index 8beee51d..dba5a388 100644 --- a/luprex/core/wrap/wrap-set.hpp +++ b/luprex/core/wrap/wrap-set.hpp @@ -6,7 +6,9 @@ namespace eng { template> -using set = std::set>; +class set : public std::set>, public eng::opnew { + using std::set>::set; +}; } // namespace eng #endif // WRAP_SET_HPP diff --git a/luprex/core/wrap/wrap-sstream.hpp b/luprex/core/wrap/wrap-sstream.hpp index 60ed91b5..785dfcbe 100644 --- a/luprex/core/wrap/wrap-sstream.hpp +++ b/luprex/core/wrap/wrap-sstream.hpp @@ -2,11 +2,16 @@ #define WRAP_SSTREAM_HPP #include "eng-malloc.hpp" +#include "wrap-string.hpp" #include +#include namespace eng { template> -using basic_ostringstream = std::basic_ostringstream>; +class basic_ostringstream : public std::basic_ostringstream>, public eng::opnew { + using underlying = std::basic_ostringstream>; + using underlying::basic_ostringstream; +}; using ostringstream = basic_ostringstream; } // namespace eng diff --git a/luprex/core/wrap/wrap-unordered-map.hpp b/luprex/core/wrap/wrap-unordered-map.hpp index 0a3ecd23..5b187f41 100644 --- a/luprex/core/wrap/wrap-unordered-map.hpp +++ b/luprex/core/wrap/wrap-unordered-map.hpp @@ -6,7 +6,9 @@ namespace eng { template, class E=std::equal_to> -using unordered_map = std::unordered_map>>; +class unordered_map : public std::unordered_map>>, public eng::opnew { + using std::unordered_map>>::unordered_map; +}; } // namespace eng #endif // WRAP_UNORDERED_MAP_HPP diff --git a/luprex/core/wrap/wrap-unordered-set.hpp b/luprex/core/wrap/wrap-unordered-set.hpp index 8854b006..08640258 100644 --- a/luprex/core/wrap/wrap-unordered-set.hpp +++ b/luprex/core/wrap/wrap-unordered-set.hpp @@ -6,7 +6,9 @@ namespace eng { template, class E=std::equal_to> -using unordered_set = std::unordered_set>; +class unordered_set : public std::unordered_set>, public eng::opnew { + using std::unordered_set>::unordered_set; +}; } // namespace eng #endif // WRAP_UNORDERED_SET_HPP diff --git a/luprex/core/wrap/wrap-vector.hpp b/luprex/core/wrap/wrap-vector.hpp index a9cb254b..30a273d0 100644 --- a/luprex/core/wrap/wrap-vector.hpp +++ b/luprex/core/wrap/wrap-vector.hpp @@ -6,7 +6,9 @@ namespace eng { template -using vector = std::vector>; +class vector : public std::vector>, public eng::opnew { + using std::vector>::vector; +}; } // namespace eng #endif // WRAP_VECTOR_HPP