diff --git a/CMakeLists.txt b/CMakeLists.txt index 943cf43..c71bfa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,19 @@ cmake_minimum_required(VERSION 3.25) -project(bluelib C) +project(bluelib C CXX) include (TestBigEndian) set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_EXTENSIONS OFF) +set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -set(b_modules core ds serial term cmd io compress) +set(b_modules + core ds serial term cmd io compress + core-mm) set(b_system_name ${CMAKE_SYSTEM_NAME}) string(TOLOWER ${b_system_name} b_system_name) @@ -37,7 +41,7 @@ foreach (module ${b_modules}) endif () - file(GLOB test_sources test/${module}/*.c) + file(GLOB test_sources test/${module}/*.c test/${module}/*.cpp) list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c") foreach (test_file ${test_sources}) diff --git a/core-mm/CMakeLists.txt b/core-mm/CMakeLists.txt new file mode 100644 index 0000000..0bc1e0c --- /dev/null +++ b/core-mm/CMakeLists.txt @@ -0,0 +1,6 @@ +include(../cmake/Templates.cmake) + +add_bluelib_mm_module( + NAME core + DEPENDENCIES core + SUBDIRS hash) diff --git a/core-mm/encoding.cpp b/core-mm/encoding.cpp new file mode 100644 index 0000000..e199c62 --- /dev/null +++ b/core-mm/encoding.cpp @@ -0,0 +1 @@ +#include diff --git a/core-mm/include/blue/core.hpp b/core-mm/include/blue/core.hpp new file mode 100644 index 0000000..e69de29 diff --git a/core-mm/include/blue/core/encoding.hpp b/core-mm/include/blue/core/encoding.hpp new file mode 100644 index 0000000..0ac7e71 --- /dev/null +++ b/core-mm/include/blue/core/encoding.hpp @@ -0,0 +1,106 @@ +#ifndef BLUE_CORE_ENCODING_HPP_ +#define BLUE_CORE_ENCODING_HPP_ + +#include +#include +#include + +namespace blue::core +{ +class wchar +{ + public: + static const int32_t INVALID = B_WCHAR_INVALID; + + wchar(); + wchar(std::int32_t v) + : val_(v) + { + } + static wchar decode(const char *s); + + operator int32_t() const + { + return val_; + } + + bool is_alpha(void) const + { + return b_wchar_is_alpha(val_); + } + bool is_number(void) const + { + return b_wchar_is_number(val_); + } + bool is_bin_digit(void) const + { + return b_wchar_is_bin_digit(val_); + } + bool is_oct_digit(void) const + { + return b_wchar_is_oct_digit(val_); + } + bool is_hex_digit(void) const + { + return b_wchar_is_hex_digit(val_); + } + bool is_space(void) const + { + return b_wchar_is_space(val_); + } + bool is_alnum(void) const + { + return b_wchar_is_alnum(val_); + } + bool is_punct(void) const + { + return b_wchar_is_punct(val_); + } + + bool is_valid_utf8_scalar(void) const + { + return b_wchar_utf8_is_valid_scalar(val_); + } + unsigned int get_utf8_codepoint_size(void) const + { + return b_wchar_utf8_codepoint_size(val_); + } + + unsigned int encode_utf8(char s[4]) const + { + return b_wchar_utf8_codepoint_encode(val_, s); + } + + private: + int32_t val_ = B_WCHAR_INVALID; +}; + +class utf8 +{ + public: + static unsigned int decode_header(char c) + { + return b_wchar_utf8_header_decode(c); + } + static unsigned int get_codepoint_stride(const char *s) + { + return b_wchar_utf8_codepoint_stride(s); + } + static std::size_t get_codepoint_count(const char *s, std::size_t nr_bytes) + { + return b_wchar_utf8_codepoint_count(s, nr_bytes); + } + static std::size_t get_string_encoded_size( + const wchar *s, std::size_t nr_codepoints) + { + return b_wchar_utf8_string_encoded_size( + reinterpret_cast(s), nr_codepoints); + } + + private: + utf8() = delete; + ~utf8() = delete; +}; +} + +#endif diff --git a/core-mm/include/blue/core/misc.hpp b/core-mm/include/blue/core/misc.hpp new file mode 100644 index 0000000..bf61c16 --- /dev/null +++ b/core-mm/include/blue/core/misc.hpp @@ -0,0 +1,46 @@ +#ifndef BLUE_CORE_MISC_HPP_ +#define BLUE_CORE_MISC_HPP_ + +#define Z__B_ENUM_CLASS_BITWISE_OPS(enum_name) \ + inline constexpr enum_name operator&(enum_name x, enum_name y) \ + { \ + return static_cast( \ + static_cast(x) & static_cast(y)); \ + } \ + \ + inline constexpr enum_name operator|(enum_name x, enum_name y) \ + { \ + return static_cast( \ + static_cast(x) | static_cast(y)); \ + } \ + \ + inline constexpr enum_name operator^(enum_name x, enum_name y) \ + { \ + return static_cast( \ + static_cast(x) ^ static_cast(y)); \ + } \ + \ + inline constexpr enum_name operator~(enum_name x) \ + { \ + return static_cast(~static_cast(x)); \ + } \ + \ + inline enum_name &operator&=(enum_name &x, enum_name y) \ + { \ + x = x & y; \ + return x; \ + } \ + \ + inline enum_name &operator|=(enum_name &x, enum_name y) \ + { \ + x = x | y; \ + return x; \ + } \ + \ + inline enum_name &operator^=(enum_name &x, enum_name y) \ + { \ + x = x ^ y; \ + return x; \ + } + +#endif diff --git a/core-mm/include/blue/core/object.hpp b/core-mm/include/blue/core/object.hpp new file mode 100644 index 0000000..9ffe07e --- /dev/null +++ b/core-mm/include/blue/core/object.hpp @@ -0,0 +1,40 @@ +#ifndef BLUE_CORE_OBJECT_HPP_ +#define BLUE_CORE_OBJECT_HPP_ + +#include + +namespace blue::core +{ +class type; +class object +{ + public: + static const size_t MAGIC = B_OBJECT_MAGIC; + object(object &) = delete; + object(object &&); + + ~object(); + + bool operator!() + { + return ptr_ == nullptr; + } + + void to_string(void) const; + bool is_type(const type &type) const; + b_object *ptr(void) + { + return ptr_; + } + const b_object *ptr(void) const + { + return ptr_; + } + + protected: + object() = default; + b_object *ptr_ = nullptr; +}; +} + +#endif diff --git a/core-mm/include/blue/core/status.hpp b/core-mm/include/blue/core/status.hpp new file mode 100644 index 0000000..7fd4599 --- /dev/null +++ b/core-mm/include/blue/core/status.hpp @@ -0,0 +1,62 @@ +#ifndef BLUE_CORE_STATUS_HPP_ +#define BLUE_CORE_STATUS_HPP_ + +#include + +namespace blue +{ +class status +{ + public: +#define __MM_STATUS_ENUM(name) name = B_ERR_##name + enum _status : int { + SUCCESS = B_SUCCESS, + __MM_STATUS_ENUM(NO_MEMORY), + __MM_STATUS_ENUM(OUT_OF_BOUNDS), + __MM_STATUS_ENUM(INVALID_ARGUMENT), + __MM_STATUS_ENUM(NAME_EXISTS), + __MM_STATUS_ENUM(NOT_SUPPORTED), + __MM_STATUS_ENUM(BAD_STATE), + __MM_STATUS_ENUM(NO_ENTRY), + __MM_STATUS_ENUM(NO_DATA), + __MM_STATUS_ENUM(NO_SPACE), + __MM_STATUS_ENUM(UNKNOWN_FUNCTION), + __MM_STATUS_ENUM(BAD_FORMAT), + __MM_STATUS_ENUM(IO_FAILURE), + __MM_STATUS_ENUM(IS_DIRECTORY), + __MM_STATUS_ENUM(NOT_DIRECTORY), + __MM_STATUS_ENUM(PERMISSION_DENIED), + __MM_STATUS_ENUM(BUSY), + __MM_STATUS_ENUM(COMPRESSION_FAILURE), + __MM_STATUS_ENUM(TYPE_REGISTRATION_FAILURE), + __MM_STATUS_ENUM(CLASS_INIT_FAILURE), + }; + + status() = default; + status(_status v) + : v_(static_cast(v)) + { + } + status(b_status v) + : v_(v) + { + } + + bool operator!() const + { + return v_ != B_SUCCESS; + } + + operator b_status() const + { + return v_; + } + const char *to_string(void); + const char *description(void); + + private: + b_status v_ = B_SUCCESS; +}; +} + +#endif diff --git a/core-mm/include/blue/core/stream.hpp b/core-mm/include/blue/core/stream.hpp new file mode 100644 index 0000000..0ea8b21 --- /dev/null +++ b/core-mm/include/blue/core/stream.hpp @@ -0,0 +1,135 @@ +#ifndef BLUE_CORE_STREAM_HPP_ +#define BLUE_CORE_STREAM_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace blue::core +{ +class stream_buffer : public object +{ +}; + +class stream : public object +{ + public: + enum class mode : int { + READ = B_STREAM_READ, + WRITE = B_STREAM_WRITE, + BINARY = B_STREAM_BINARY, + __STATIC = Z__B_STREAM_STATIC, + }; + + enum class seek_origin : int { + START = B_STREAM_SEEK_START, + CURRENT = B_STREAM_SEEK_CURRENT, + END = B_STREAM_SEEK_END, + }; + + static type get_type(void); + static stream &in(void); + static stream &out(void); + static stream &err(void); + + stream(stream &) = delete; + + stream(std::FILE *fp); + + status reserve(std::size_t len); + status seek(long long offset, seek_origin origin); + std::size_t cursor(void) const; + + status push_indent(int indent); + status pop_indent(void); + + status read_char(wchar &c); + + status read_bytes(void *buf, std::size_t count, std::size_t &nr_read); + status read_bytes(void *buf, std::size_t count) + { + std::size_t tmp; + return read_bytes(buf, count, tmp); + } + + status read_line(char *s, std::size_t max); + status read_line(std::string &out); + status read_line(stream &dest); + + status read_all_bytes(void *p, std::size_t max, std::size_t &nr_read); + status read_all_bytes( + stream &dest, stream_buffer &buf, std::size_t &nr_read); + + status read_all_bytes(void *p, std::size_t max) + { + std::size_t tmp; + return read_all_bytes(p, max); + } + + status read_all_bytes(stream &dest, stream_buffer &buf) + { + std::size_t tmp; + return read_all_bytes(dest, buf); + } + + status write_char(wchar c); + status write_string(const char *s, std::size_t &nr_written); + status write_string(const char *s) + { + std::size_t tmp; + return write_string(s, tmp); + } + + status write_string(const std::string &s, std::size_t &nr_written) + { + return write_string(s.c_str(), nr_written); + } + status write_string(const std::string &s) + { + std::size_t tmp; + return write_string(s, tmp); + } + + status write_bytes( + const void *buf, std::size_t count, std::size_t &nr_written); + status write_bytes(const void *buf, std::size_t count) + { + std::size_t tmp; + return write_bytes(buf, count, tmp); + } + + status write_fmt(std::size_t &nr_written, const char *format, ...); + status write_vfmt( + std::size_t &nr_written, const char *format, std::va_list arg); + + status write_fmt(const char *format, ...) + { + std::size_t tmp; + std::va_list arg; + va_start(arg, format); + status s = write_vfmt(tmp, format, arg); + va_end(arg); + return s; + } + + status write_vfmt(const char *format, std::va_list arg) + { + std::size_t tmp; + return write_vfmt(tmp, format, arg); + } + + protected: + stream() = default; +}; +} + +Z__B_ENUM_CLASS_BITWISE_OPS(blue::core::stream::mode) + +#endif diff --git a/core-mm/include/blue/core/stringstream.hpp b/core-mm/include/blue/core/stringstream.hpp new file mode 100644 index 0000000..ec83750 --- /dev/null +++ b/core-mm/include/blue/core/stringstream.hpp @@ -0,0 +1,23 @@ +#ifndef BLUE_CORE_STRINGSTREAM_HPP_ +#define BLUE_CORE_STRINGSTREAM_HPP_ + +#include + +namespace blue::core +{ +class stringstream : public stream +{ + public: + stringstream(); + stringstream(char *buf, std::size_t max); + + status reset(); + status reset(char *buf, std::size_t max); + + const char *get_ptr() const; + char *steal_ptr(); + std::size_t get_length() const; +}; +} + +#endif diff --git a/core-mm/include/blue/core/type.hpp b/core-mm/include/blue/core/type.hpp new file mode 100644 index 0000000..670908d --- /dev/null +++ b/core-mm/include/blue/core/type.hpp @@ -0,0 +1,24 @@ +#ifndef BLUE_CORE_TYPE_HPP_ +#define BLUE_CORE_TYPE_HPP_ + +#include + +namespace blue::core +{ +class type +{ + public: + type(b_type p) + { + ptr_ = p; + } + ~type() = default; + + type(type &) = default; + + private: + const union b_type_id *ptr_; +}; +} + +#endif diff --git a/core-mm/object.cpp b/core-mm/object.cpp new file mode 100644 index 0000000..8d9ce7a --- /dev/null +++ b/core-mm/object.cpp @@ -0,0 +1,20 @@ +#include + +namespace blue::core +{ + +object::object(object &&other) +{ + ptr_ = other.ptr_; + other.ptr_ = nullptr; +} + +object::~object() +{ + if (ptr_) { + b_object_unref(ptr_); + ptr_ = nullptr; + } +} + +} diff --git a/core-mm/stream.cpp b/core-mm/stream.cpp new file mode 100644 index 0000000..6b2600e --- /dev/null +++ b/core-mm/stream.cpp @@ -0,0 +1,169 @@ +#include +#include + +namespace blue::core +{ +type stream::get_type(void) +{ + return b_stream_get_type(); +} + +stream &stream::in(void) +{ + static stream s; + s.ptr_ = b_stdin; + return s; +} + +stream &stream::out(void) +{ + static stream s; + s.ptr_ = b_stdout; + return s; +} + +stream &stream::err(void) +{ + static stream s; + s.ptr_ = b_stderr; + return s; +} + +stream::stream(std::FILE *fp) +{ + ptr_ = b_stream_open_fp(fp); +} + +status stream::reserve(std::size_t len) +{ + return b_stream_reserve(ptr_, len); +} + +status stream::seek(long long offset, seek_origin origin) +{ + return b_stream_seek( + ptr_, offset, static_cast(origin)); +} + +std::size_t stream::cursor(void) const +{ + return b_stream_cursor(ptr_); +} + +status stream::push_indent(int indent) +{ + return b_stream_push_indent(ptr_, indent); +} + +status stream::pop_indent(void) +{ + return b_stream_pop_indent(ptr_); +} + +status stream::read_char(wchar &c) +{ + b_wchar tmp; + status s = b_stream_read_char(ptr_, &tmp); + c = tmp; + return s; +} + +status stream::read_bytes(void *buf, std::size_t count, std::size_t &nr_read) +{ + std::size_t r; + status s = b_stream_read_bytes(ptr_, buf, count, &r); + nr_read = r; + return s; +} + +status stream::read_line(char *s, std::size_t max) +{ + return b_stream_read_line(ptr_, s, max); +} + +status stream::read_line(std::string &out) +{ + while (1) { + wchar c = wchar::INVALID; + status s = read_char(c); + if (!s) { + return s; + } + + if (c == '\n') { + break; + } + + char str[5] = {0}; + c.encode_utf8(str); + out.append(str); + } + + return status::SUCCESS; +} + +status stream::read_line(stream &dest) +{ + return b_stream_read_line_s(ptr_, dest.ptr_); +} + +status stream::read_all_bytes(void *p, std::size_t max, std::size_t &nr_read) +{ + std::size_t tmp; + status s = b_stream_read_all_bytes(ptr_, p, max, &tmp); + nr_read = tmp; + return s; +} + +status stream::read_all_bytes(stream &dest, stream_buffer &buf, std::size_t &nr_read) +{ + std::size_t tmp; + status s = b_stream_read_all_bytes_s(ptr_, dest.ptr_, buf.ptr(), &tmp); + nr_read = tmp; + return s; +} + +status stream::write_char(wchar c) +{ + return b_stream_write_char(ptr_, c); +} + +status stream::write_string(const char *str, std::size_t &nr_written) +{ + std::size_t tmp; + status s = b_stream_write_string(ptr_, str, &tmp); + nr_written = tmp; + return s; +} + +status stream::write_bytes( + const void *buf, std::size_t count, std::size_t &nr_written) +{ + std::size_t tmp; + status s = b_stream_write_bytes(ptr_, buf, count, &tmp); + nr_written = tmp; + return s; +} + +status stream::write_fmt(std::size_t &nr_written, const char *format, ...) +{ + size_t tmp; + std::va_list arg; + va_start(arg, format); + status s = b_stream_write_vfmt(ptr_, &tmp, format, arg); + va_end(arg); + + nr_written = tmp; + return s; +} + +status stream::write_vfmt(std::size_t &nr_written, const char *format, va_list arg) +{ + size_t tmp; + status s = b_stream_write_vfmt(ptr_, &tmp, format, arg); + + nr_written = tmp; + return s; +} + +} diff --git a/core-mm/stringstream.cpp b/core-mm/stringstream.cpp new file mode 100644 index 0000000..e2fe116 --- /dev/null +++ b/core-mm/stringstream.cpp @@ -0,0 +1,42 @@ +#include +#include + +namespace blue::core +{ + +stringstream::stringstream() +{ + ptr_ = b_stringstream_create(); +} + +stringstream::stringstream(char *buf, std::size_t max) +{ + ptr_ = b_stringstream_create_with_buffer(buf, max); +} + +status stringstream::reset() +{ + return b_stringstream_reset(ptr_); +} + +status stringstream::reset(char *buf, std::size_t max) +{ + return b_stringstream_reset_with_buffer(ptr_, buf, max); +} + +const char *stringstream::get_ptr() const +{ + return b_stringstream_ptr(ptr_); +} + +char *stringstream::steal_ptr() +{ + return b_stringstream_steal(ptr_); +} + +std::size_t stringstream::get_length() const +{ + return b_stringstream_get_length(ptr_); +} + +} diff --git a/core-mm/type.cpp b/core-mm/type.cpp new file mode 100644 index 0000000..7cef22f --- /dev/null +++ b/core-mm/type.cpp @@ -0,0 +1 @@ +#include