diff options
author | Eugene Kosov <claprix@yandex.ru> | 2021-03-22 22:12:50 +0300 |
---|---|---|
committer | Eugene Kosov <claprix@yandex.ru> | 2021-03-24 11:23:12 +0300 |
commit | 8094640809804f74f9d51c9c50a368ecad4f7cb1 (patch) | |
tree | 393c348a07310174598bfb6b0811367e2579d4aa | |
parent | cb545f11169d2425316d96feafc78ac841950e43 (diff) | |
download | mariadb-git-bb-10.6-MDEV-20453.tar.gz |
MDEV-20453 add class similar to std::string_view (non owning string reference)bb-10.6-MDEV-20453
Also use string_view in some places.
-rw-r--r-- | include/string_view.h | 417 | ||||
-rw-r--r-- | sql/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sql/string_view.cc | 25 | ||||
-rw-r--r-- | storage/innobase/dict/dict0mem.cc | 41 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 47 | ||||
-rw-r--r-- | storage/innobase/fsp/fsp0file.cc | 26 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 28 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 7 | ||||
-rw-r--r-- | storage/innobase/include/log0log.h | 2 |
9 files changed, 502 insertions, 92 deletions
diff --git a/include/string_view.h b/include/string_view.h new file mode 100644 index 00000000000..88ec70fcd74 --- /dev/null +++ b/include/string_view.h @@ -0,0 +1,417 @@ +/***************************************************************************** +Copyright (c) 2021 MariaDB Corporation. +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +*****************************************************************************/ + +#ifndef STRING_VIEW_H +#define STRING_VIEW_H + +#include <cassert> +#include <cstddef> + +#include <algorithm> +#include <iosfwd> +#include <iterator> +#include <limits> +#include <memory> +#include <stdexcept> +#include <string> + +#include "my_attribute.h" + +class string_view +{ +public: + using traits_type= std::char_traits<char>; + using value_type= char; + using pointer= char *; + using const_pointer= const char *; + using reference= char &; + using const_reference= const char &; + using const_iterator= const char *; + using iterator= const_iterator; + using const_reverse_iterator= std::reverse_iterator<const_iterator>; + using reverse_iterator= const_reverse_iterator; + using size_type= std::size_t; + using difference_type= std::ptrdiff_t; + + static constexpr size_type npos= size_type(-1); + + constexpr string_view() noexcept : str_(nullptr), size_(0) {} + constexpr string_view(const string_view &rhs) noexcept= default; + constexpr string_view(const char *s, size_type count) : str_(s), size_(count) + { + } + string_view(const char *s) : str_(s), size_(traits_type::length(s)) {} + // In C++20 it's different. + template <class It> + constexpr string_view(It first, It last) : str_(&*first), size_(last - first) + { + } + // Add such ctor because we can't add string_view operator to std::string + string_view(const std::string &s) noexcept : str_(s.data()), size_(s.size()) + { + } + + string_view &operator=(const string_view &rhs) + { + str_= rhs.str_; + size_= rhs.size_; + return *this; + } + + constexpr const_iterator begin() const noexcept { return str_; } + constexpr const_iterator cbegin() const noexcept { return str_; } + + constexpr const_iterator end() const noexcept { return str_ + size_; } + constexpr const_iterator cend() const noexcept { return str_ + size_; } + + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } + + constexpr const_reference operator[](size_type pos) const noexcept + { + return str_[pos]; + } + + const_reference at(size_type pos) const + { + if (pos >= size()) + throw std::out_of_range("string_view::at()"); + + return str_[pos]; + } + + constexpr const_reference front() const noexcept { return operator[](0); } + constexpr const_reference back() const noexcept + { + return operator[](size() - 1); + } + + constexpr const_pointer data() const noexcept { return str_; } + + constexpr size_type size() const noexcept { return size_; } + constexpr size_type length() const noexcept { return size_; } + + constexpr size_type max_size() const noexcept + { + return std::numeric_limits<size_type>::max(); + } + + constexpr __attribute__((warn_unused_result)) bool empty() const noexcept + { + return size() == 0; + } + + void remove_prefix(size_type n) + { + assert(n <= size()); + str_+= n; + size_-= n; + } + + void remove_suffix(size_type n) + { + assert(n <= size()); + size_-= n; + } + + void swap(string_view &rhs) noexcept + { + std::swap(str_, rhs.str_); + std::swap(size_, rhs.size_); + } + + size_type copy(char *dest, size_type count, size_type pos= 0) const + { + if (pos > size()) + throw std::out_of_range("string_view::copy()"); + + auto rcount= std::min(size() - pos, count); + traits_type::copy(dest, data() + pos, rcount); + return rcount; + } + + string_view substr(size_type pos= 0, size_type count= npos) const + { + if (pos > size()) + throw std::out_of_range("string_view::substr()"); + + auto rcount= std::min(size() - pos, count); + return {data() + pos, pos + rcount}; + } + + int compare(string_view v) const noexcept + { + auto rlen= std::min(size(), v.size()); + return traits_type::compare(data(), v.data(), rlen); + } + int compare(size_type pos1, size_type count1, string_view v) const + { + return substr(pos1, count1).compare(v); + } + int compare(size_type pos1, size_type count1, string_view v, size_type pos2, + size_type count2) const + { + return substr(pos1, count1).compare(v.substr(pos2, count2)); + } + int compare(const char *s) const { return compare(string_view(s)); } + int compare(size_type pos1, size_type count1, const char *s) const + { + return substr(pos1, count1).compare(string_view(s)); + } + int compare(size_type pos1, size_type count1, const char *s, + size_type count2) const + { + return substr(pos1, count1).compare(string_view(s, count2)); + } + + bool starts_with(string_view sv) const noexcept + { + return substr(0, sv.size()) == sv; + } + constexpr bool starts_with(char c) const noexcept + { + return !empty() && traits_type::eq(front(), c); + } + bool starts_with(const char *s) const { return starts_with(string_view(s)); } + + bool ends_with(string_view sv) const noexcept + { + return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0; + } + constexpr bool ends_with(char c) const noexcept + { + return !empty() && traits_type::eq(back(), c); + } + bool ends_with(const char *s) const { return ends_with(string_view(s)); } + + bool contains(string_view sv) const noexcept { return find(sv) != npos; } + bool contains(char c) const noexcept { return find(c) != npos; } + bool contains(const char *s) const { return find(s) != npos; } + + size_type find(string_view v, size_type pos= 0) const noexcept + { + // TODO: optimize with std::strstr() + auto it= std::search(begin() + pos, end(), v.begin(), v.end()); + if (it == end()) + return npos; + return it - begin(); + } + size_type find(char ch, size_type pos= 0) const noexcept + { + return find(string_view(std::addressof(ch), 1)); + } + size_type find(const char *s, size_type pos, size_type count) const + { + return find(string_view(s, count), pos); + } + size_type find(const char *s, size_type pos= 0) const + { + return find(string_view(s), pos); + } + + size_type rfind(string_view v, size_type pos= npos) const noexcept + { + assert(!v.empty()); + + if (empty()) + return npos; + + pos= std::min(size() - 1, pos); + + if (v.size() > pos + 1) + return npos; + + pos-= v.size(); + + for (;; --pos) + { + string_view tmp(str_ + pos, v.size()); + if (tmp == v) + return pos; + + if (pos == 0) + break; + } + + return npos; + } + size_type rfind(char c, size_type pos= npos) const noexcept + { + return rfind(string_view(std::addressof(c), 1), pos); + } + size_type rfind(const char *s, size_type pos, size_type count) const + { + return rfind(string_view(s, count), pos); + } + size_type rfind(const char *s, size_type pos= npos) const + { + return rfind(string_view(s), pos); + } + + size_type find_first_of(string_view v, size_type pos= 0) const noexcept + { + // TODO: optimize with a lookup table. + auto it= std::find_if(begin() + pos, end(), + [v](char c) { return v.find(c) != npos; }); + if (it == end()) + return npos; + return it - begin(); + } + size_type find_first_of(char c, size_type pos= 0) const noexcept + { + return find_first_of(string_view(std::addressof(c), 1), pos); + } + size_type find_first_of(const char *s, size_type pos, size_type count) const + { + return find_first_of(string_view(s, count), pos); + } + size_type find_first_of(const char *s, size_type pos= 0) const + { + return find_first_of(string_view(s), pos); + } + + size_type find_last_of(string_view v, size_type pos= npos) const noexcept + { + // TODO: optimize with a lookup table. + auto it= std::find_if(reverse_iterator(begin() + pos), rend(), + [v](char c) { return v.find(c) != npos; }); + if (it == rend()) + return npos; + return it.base() - begin(); + } + size_type find_last_of(char c, size_type pos= npos) const noexcept + { + return find_last_of(string_view(std::addressof(c), 1), pos); + } + size_type find_last_of(const char *s, size_type pos, size_type count) const + { + return find_last_of(string_view(s, count), pos); + } + size_type find_last_of(const char *s, size_type pos= npos) const + { + return find_last_of(string_view(s), pos); + } + + size_type find_first_not_of(string_view v, size_type pos= 0) const noexcept + { + // TODO: optimize with a lookup table. + auto it= std::find_if(begin() + pos, end(), + [v](char c) { return v.find(c) == npos; }); + if (it == end()) + return npos; + return it - begin(); + } + size_type find_first_not_of(char c, size_type pos= 0) const noexcept + { + return find_first_not_of(string_view(std::addressof(c), 1), pos); + } + size_type find_first_not_of(const char *s, size_type pos, + size_type count) const + { + return find_first_not_of(string_view(s, count), pos); + } + size_type find_first_not_of(const char *s, size_type pos= 0) const + { + return find_first_not_of(string_view(s), pos); + } + + size_type find_last_not_of(string_view v, size_type pos= npos) const noexcept + { + // TODO: optimize with a lookup table. + auto it= std::find_if(reverse_iterator(begin() + pos), rend(), + [v](char c) { return v.find(c) == npos; }); + if (it == rend()) + return npos; + return it.base() - begin(); + } + size_type find_last_not_of(char c, size_type pos= npos) const noexcept + { + return find_last_not_of(string_view(std::addressof(c), 1), pos); + } + size_type find_last_not_of(const char *s, size_type pos, + size_type count) const + { + return find_last_not_of(string_view(s, count), pos); + } + size_type find_last_not_of(const char *s, size_type pos= npos) const + { + return find_last_not_of(string_view(s), pos); + } + + friend bool operator==(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + friend bool operator<(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(string_view lhs, string_view rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + +private: + const_pointer str_= nullptr; + size_type size_= 0; +}; + +std::basic_ostream<char> &operator<<(std::basic_ostream<char> &os, + string_view v); + +namespace std +{ + +template <> struct hash<string_view> +{ + size_t operator()(string_view v) + { + uint32_t hash= 0; + + for (char c : v) + hash= (hash * 2166136261u) ^ static_cast<uint32_t>(c); + + return static_cast<size_t>(hash); + } +}; + +} // namespace std + +#endif diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 9f44eee1f96..6185b74aac5 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -165,6 +165,7 @@ SET (SQL_SOURCE opt_trace.cc table_cache.cc encryption.cc temporary_tables.cc proxy_protocol.cc backup.cc xa.cc + string_view.cc ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h ${GEN_SOURCES} diff --git a/sql/string_view.cc b/sql/string_view.cc new file mode 100644 index 00000000000..6b3b101c131 --- /dev/null +++ b/sql/string_view.cc @@ -0,0 +1,25 @@ +/***************************************************************************** +Copyright (c) 2021 MariaDB Corporation. +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +*****************************************************************************/ + +#include "string_view.h" + +#include <ostream> + +std::basic_ostream<char> &operator<<(std::basic_ostream<char> &os, + string_view v) +{ + // TODO standard requires a much more complicated code here. + auto size= static_cast<std::streamsize>(v.size()); + os.write(v.data(), size); + return os; +} diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index f4a56faaf28..667ec29f6c8 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -37,40 +37,37 @@ Created 1/8/1996 Heikki Tuuri #include "lock0lock.h" #include "row0row.h" #include "sql_string.h" +#include "string_view.h" #include <iostream> #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when creating a table or index object */ /** System databases */ -static const char* innobase_system_databases[] = { - "mysql/", - "information_schema/", - "performance_schema/", - NullS +static const string_view innobase_system_databases[]= { + "mysql/", + "information_schema/", + "performance_schema/", }; /** Determine if a table belongs to innobase_system_databases[] @param[in] name database_name/table_name @return whether the database_name is in innobase_system_databases[] */ -static bool dict_mem_table_is_system(const char *name) +static bool dict_mem_table_is_system(string_view name) { - /* table has the following format: database/table - and some system table are of the form SYS_* */ - if (!strchr(name, '/')) { - return true; - } - size_t table_len = strlen(name); - const char *system_db; - int i = 0; - while ((system_db = innobase_system_databases[i++]) - && (system_db != NullS)) { - size_t len = strlen(system_db); - if (table_len > len && !strncmp(name, system_db, len)) { - return true; - } - } - return false; + /* table has the following format: database/table + and some system table are of the form SYS_* */ + if (!name.contains('/')) + return true; + for (auto system_db : innobase_system_databases) + { + if (name.size() > system_db.size() && + system_db == name.substr(0, system_db.size())) + { + return true; + } + } + return false; } /** The start of the table basename suffix for partitioned tables */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 7eb3abfbf21..f036b728e00 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2692,53 +2692,6 @@ fil_space_read_name_and_filepath( return(success); } -/** Convert a file name to a tablespace name. -@param[in] filename directory/databasename/tablename.ibd -@return database/tablename string, to be freed with ut_free() */ -char* -fil_path_to_space_name( - const char* filename) -{ - /* Strip the file name prefix and suffix, leaving - only databasename/tablename. */ - ulint filename_len = strlen(filename); - const char* end = filename + filename_len; -#ifdef HAVE_MEMRCHR - const char* tablename = 1 + static_cast<const char*>( - memrchr(filename, OS_PATH_SEPARATOR, - filename_len)); - const char* dbname = 1 + static_cast<const char*>( - memrchr(filename, OS_PATH_SEPARATOR, - tablename - filename - 1)); -#else /* HAVE_MEMRCHR */ - const char* tablename = filename; - const char* dbname = NULL; - - while (const char* t = static_cast<const char*>( - memchr(tablename, OS_PATH_SEPARATOR, - ulint(end - tablename)))) { - dbname = tablename; - tablename = t + 1; - } -#endif /* HAVE_MEMRCHR */ - - ut_ad(dbname != NULL); - ut_ad(tablename > dbname); - ut_ad(tablename < end); - ut_ad(end - tablename > 4); - ut_ad(memcmp(end - 4, DOT_IBD, 4) == 0); - - char* name = mem_strdupl(dbname, ulint(end - dbname) - 4); - - ut_ad(name[tablename - dbname - 1] == OS_PATH_SEPARATOR); -#if OS_PATH_SEPARATOR != '/' - /* space->name uses '/', not OS_PATH_SEPARATOR. */ - name[tablename - dbname - 1] = '/'; -#endif - - return(name); -} - /** Discover the correct IBD file to open given a remote or missing filepath from the REDO log. Administrators can move a crashed database to another location on the same machine and try to recover it. diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index 57164113647..69ffae15543 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -30,6 +30,8 @@ Created 2013-7-26 by Kevin Lewis #include "page0page.h" #include "srv0start.h" +#include "string_view.h" + /** Initialize the name, size and order of this datafile @param[in] name tablespace name, will be copied @param[in] flags tablespace flags */ @@ -258,6 +260,28 @@ Datafile::same_as( #endif /* WIN32 */ } +/** Convert a file name to a tablespace name. +@param[in] filename directory/databasename/tablename.ibd +@return database/tablename string, to be freed with ut_free() */ +static char *fsp_path_to_space_name(string_view filename) +{ + auto last_slash= filename.rfind(OS_PATH_SEPARATOR); + auto prev_last_slash= + filename.substr(0, last_slash).rfind(OS_PATH_SEPARATOR); + filename.remove_prefix(prev_last_slash + 1); + ut_ad(filename.ends_with(DOT_IBD)); + filename.remove_suffix(strlen(DOT_IBD)); + + char *name= mem_strdupl(filename.data(), filename.size()); + +#if OS_PATH_SEPARATOR != '/' + /* space->name uses '/', not OS_PATH_SEPARATOR. */ + name[last_slash - prev_last_slash - 1]= '/'; +#endif + + return name; +} + /** Allocate and set the datafile or tablespace name in m_name. If a name is provided, use it; else extract a file-per-table tablespace name from m_filepath. The value of m_name @@ -271,7 +295,7 @@ Datafile::set_name(const char* name) if (name != NULL) { m_name = mem_strdup(name); } else { - m_name = fil_path_to_space_name(m_filepath); + m_name = fsp_path_to_space_name(m_filepath); } } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 58e17cd3ead..359a3aa49c2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -30,6 +30,7 @@ Smart ALTER TABLE #include <sql_class.h> #include <sql_table.h> #include <mysql/plugin.h> +#include "string_view.h" /* Include necessary InnoDB headers */ #include "btr0sea.h" @@ -7367,27 +7368,26 @@ Rename a given index in the InnoDB data dictionary cache. @param[in,out] index index to rename @param new_name new index name */ -static -void -innobase_rename_index_cache(dict_index_t* index, const char* new_name) +static void innobase_rename_index_cache(dict_index_t *index, + string_view new_name) { - DBUG_ENTER("innobase_rename_index_cache"); - ut_d(dict_sys.assert_locked()); + DBUG_ENTER("innobase_rename_index_cache"); + ut_d(dict_sys.assert_locked()); - size_t old_name_len = strlen(index->name); - size_t new_name_len = strlen(new_name); + size_t old_name_len= strlen(index->name); - if (old_name_len < new_name_len) { - index->name = static_cast<char*>( - mem_heap_alloc(index->heap, new_name_len + 1)); - } + if (old_name_len < new_name.size()) + { + index->name= + static_cast<char *>(mem_heap_alloc(index->heap, new_name.size() + 1)); + } - memcpy(const_cast<char*>(index->name()), new_name, new_name_len + 1); + memcpy(const_cast<char *>(index->name()), new_name.data(), + new_name.size() + 1); - DBUG_VOID_RETURN; + DBUG_VOID_RETURN; } - /** Rename the index name in cache. @param[in] ctx alter context @param[in] ha_alter_info Data used during inplace alter. */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 70cbedc3a94..1d91d759d9d 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1765,13 +1765,6 @@ fil_space_read_name_and_filepath( char** name, char** filepath); -/** Convert a file name to a tablespace name. -@param[in] filename directory/databasename/tablename.ibd -@return database/tablename string, to be freed with ut_free() */ -char* -fil_path_to_space_name( - const char* filename); - /*******************************************************************//** Returns the table space by a given id, NULL if not found. */ fil_space_t* diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index a3085f0f2dd..a28f4195ee4 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -525,7 +525,7 @@ public: /** writes header */ void write_header_durable(lsn_t lsn); /** opens log file which must be closed prior this call */ - dberr_t rename(std::string path) { return fd.rename(path); } + dberr_t rename(std::string path) { return fd.rename(std::move(path)); } /** reads buffer from log file @param[in] offset offset in log file @param[in] buf buffer where to read */ |