#pragma once #ifndef SPRAWL_STRING_NO_STL_COMPAT # include <string> # include "../hash/Murmur3.hpp" #endif #include "StringCommon.hpp" #include "StringBuilder.hpp" #include <stdint.h> #include <unordered_map> #include <atomic> namespace sprawl { class StringLiteral; class String { public: class Holder { protected: friend class String; Holder(); Holder(const char* data); Holder(const char* data, size_t length); Holder(StringLiteral const& literal); void IncRef(); bool DecRef(); static Holder* CreateHolder(); static void FreeHolder(Holder* holder); ~Holder(); inline size_t GetHash() const { if(m_hashComputed) { return m_hash; } m_hash = sprawl::murmur3::Hash( m_data, m_length ); m_hashComputed = true; return m_hash; } static constexpr size_t staticDataSize = SPRAWL_STATIC_STRING_SIZE; char m_staticData[staticDataSize]; char* m_dynamicData; const char* m_data; std::atomic<int> m_refCount; size_t m_length; mutable size_t m_hash; mutable bool m_hashComputed; private: Holder(Holder const& other); Holder& operator=(Holder const& other); }; String(); String(const char* const data); String(const char* const data, size_t length); String(String const& other); String(String&& other); #ifndef SPRAWL_STRING_NO_STL_COMPAT String(std::string const& stlString); #endif String(StringLiteral const& stringLiteral); ~String(); inline size_t GetHash() const { return m_holder->GetHash(); } #ifndef SPRAWL_STRING_NO_STL_COMPAT std::string toStdString() const; #endif const char* c_str() const { return m_holder->m_data; } size_t length() const { return m_holder->m_length; } String& operator=(String const& other); String& operator=(String&& other); inline bool operator==(String const& other) const { return (m_holder == other.m_holder) || ((m_holder->m_length == other.m_holder->m_length) && (SPRAWL_MEMCMP(m_holder->m_data, other.m_holder->m_data, m_holder->m_length) == 0)); } bool operator!=(String const& other) const { return !operator==(other); } sprawl::String operator+(sprawl::String const& other) const; sprawl::String operator+(const char* other) const; sprawl::String& operator+=(sprawl::String const& other); sprawl::String& operator+=(const char* other); bool empty() const { return m_holder->m_length == 0; } bool operator<(String const& other) const; char const& operator[](size_t index) const { return m_holder->m_data[index]; } String GetOwned() const; template<typename... Params> String format(Params const& ...params) { #if !SPRAWL_STRINGBUILDER_FAVOR_SPEED_OVER_MEMORY StringBuilder nullBuilder(0); ExecuteFormat(nullBuilder, params...); size_t const length = nullBuilder.Size(); StringBuilder builder(length, false); #else size_t const startingLength = m_holder->m_length * 2 + 1; StringBuilder builder(startingLength, true); #endif ExecuteFormat(builder, params...); return builder.Str(); } private: template<int idx, typename... Params> class FormatHelper; template<int idx> class FormatHelper<idx> { public: void Append(int pos, StringBuilder& builder, char* modifiers) { (void)(pos); (void)(modifiers); builder << "< ??? >"; } }; template<int idx, typename T> class FormatHelper<idx, T> : public FormatHelper<idx + 1> { public: typedef FormatHelper<idx + 1> Base; FormatHelper(T const& val) : Base() , m_value(val) { // } void Append(int pos, StringBuilder& builder, char* modifiers) { if(pos == idx) { builder.AppendElementToBuffer(m_value, modifiers); } else { Base::Append(pos, builder, modifiers); } } private: T const& m_value; }; template<int idx, typename T, typename... Params> class FormatHelper<idx, T, Params...> : public FormatHelper<idx + 1, Params...> { public: typedef FormatHelper<idx + 1, Params...> Base; FormatHelper(T const& val, Params const& ...values) : Base(values...) , m_value(val) { // } void Append(int pos, StringBuilder& builder, char* modifiers) { if(pos == idx) { builder.AppendElementToBuffer(m_value, modifiers); } else { Base::Append(pos, builder, modifiers); } } private: T const& m_value; }; template<typename... Params> void ExecuteFormat( StringBuilder& builder, Params const& ...params) { FormatHelper<0, Params...> helper(params...); int curIdx = -1; size_t lastIdx = 0; bool inBracket = false; char modifiers[10]; size_t modifierPos = 0; bool inModifiers = false; size_t const formatLength = m_holder->m_length; char const* const data = m_holder->m_data; for(size_t i = 0; i < formatLength; ++i) { const char c = data[i]; if(c == '{') { if(inBracket) { builder << '{'; } inBracket = !inBracket; continue; } if(inBracket) { if(c == '}') { modifiers[modifierPos] = '\0'; if(curIdx == -1) { helper.Append(lastIdx, builder, modifiers); ++lastIdx; } else { helper.Append(curIdx, builder, modifiers); lastIdx = curIdx + 1; } modifiers[0] = '\0'; modifierPos = 0; curIdx = -1; inBracket = false; inModifiers = false; } else if(c == ':' && !inModifiers) { inModifiers = true; } else if(inModifiers) { modifiers[modifierPos++] = c; } else if(isdigit(c)) { if(curIdx == -1) { curIdx = c - '0'; } else { curIdx *= 10; curIdx += c - '0'; } } else { builder << '{'; if(curIdx != -1) { builder << curIdx; } builder << c; inBracket = false; } continue; } builder << c; } } private: Holder* m_holder; static Holder ms_emptyHolder; }; class StringLiteral { public: template<size_t N> StringLiteral(const char (&ptr)[N]) : m_ptr(ptr) , m_length(N-1) { // } explicit StringLiteral(const char* ptr, size_t length) : m_ptr(ptr) , m_length(length) { // } const char* GetPtr() const { return m_ptr; } size_t GetLength() const { return m_length; } bool operator==(StringLiteral const& other) const { return m_ptr == other.m_ptr; } bool operator!=(StringLiteral const& other) const { return m_ptr != other.m_ptr; } protected: friend class String::Holder; char const* m_ptr; size_t m_length; }; typedef StringLiteral StringRef; template<typename... Params> sprawl::String Format(const char* const text, Params&&... params) { return sprawl::String(sprawl::StringLiteral(text, strlen(text))).format(std::forward<Params>(params)...); } } #ifndef SPRAWL_STRING_NO_STL_COMPAT namespace std { template<> struct hash<sprawl::String> { typedef sprawl::String argument_type; typedef std::size_t value_type; inline value_type operator()(argument_type const& str) const { return str.GetHash(); } }; template<> struct hash<sprawl::StringLiteral> { typedef sprawl::StringLiteral argument_type; typedef std::size_t value_type; inline value_type operator()(argument_type const& str) const { return sprawl::murmur3::HashPointer(intptr_t(str.GetPtr())); } }; } #endif #ifndef _WIN32 #ifndef SPRAWL_NO_FORMAT_LITERAL namespace sprawl { namespace detail { class FormatHelper { public: template<size_t N> FormatHelper(const char (&ptr)[N]) : m_str(StringLiteral(ptr)) { // } explicit FormatHelper(const char* ptr, size_t length) : m_str(StringLiteral(ptr, length)) { // } template<typename... Params> sprawl::String operator()(Params&&... params) { return m_str.format(std::forward<Params>(params)...); } private: String m_str; }; } } inline sprawl::detail::FormatHelper operator "" _format(const char *ptr, size_t length) { return sprawl::detail::FormatHelper(ptr, length); } #endif #endif
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#12 | 19906 | ShadauxCat |
- Added tag, compile time string type - Since tag requires visual studio 2015, removed compatibility code for earlier versions of visual studio - Improved compiler detection - Added endianness detection - Added template if/else helper - Fixed bug with murmur3 64 bit - Added seed argument for murmur3 #review-19907 |
||
#11 | 14833 | ShadauxCat |
First checkin of logging module. Also fixes the following issues: -Added UpperBound() and LowerBound() to BinaryTree and created appropriate unit tests -Added Sync() to ThreadManager to force it to run all tasks to completion and not return until it has no tasks left -Fixed a bug in String::format() where a non-numeric value inside {} would be treated as an empty {}; it now simply prints whatever the value was. (i.e., "{blah}".format(foo) simply returns "{blah}") -Added Reset() to sprawl::StringBuilder -Disabled the switch-enum warning flag in gcc because it's stupid and ridiculous that a default case doesn't shut it up -Made sprawl::Mutex movable. This may turn out to be a bad idea but it enabled keeping them in a map. -Fixed a name collission between HashMap and BinaryTree; both defined sprawl::collections::detail::UnderlyingType and ::MethodType. Prefixed the ones in BinaryTree with "Tree". This isn't the best solution, but it works for now. #review-14834 |
||
#10 | 14816 | ShadauxCat |
Filled in some more filesystem functions, added appropriate unit tests. Only a few remain. #review-14817 |
||
#9 | 14783 | ShadauxCat |
Style corrections (placement of const) #review-14784 |
||
#8 | 14771 | ShadauxCat |
Sadface. User-defined literals not supported in visual studio 2013. Disabled for win32. #review-14772 |
||
#7 | 14769 | ShadauxCat |
Added string literal to allow format strings to be used in a way that's closer to python: "{} {} {}"_format(foo, bar, baz); .format() would be great, but not possible; _format() is almost as good. #review-14770 |
||
#6 | 14761 | ShadauxCat |
First drop of code for sprawl::filesystem and sprawl::path. Library will continue to grow. Also fixed a warning on linux. #review-14762 |
||
#5 | 14146 | ShadauxCat |
Moving a gtest-specific function out of String.hpp #review-14147 |
||
#4 | 14144 | ShadauxCat |
Switching unit tests to gtest. 100 is a decent number of tests to start with, but it needs to be more like 400 to test the current codebase. #review-14145 |
||
#3 | 14015 | ShadauxCat |
-Made reference counts in strings atomic -Fixed an issue where items that were implicitly convertible to a hash map's value could not be inserted without explicit construction. (i.e., inserting a String object as map.insert("myString") would fail; it had to be map.insert(sprawl::String("myString"))) -Added template aliases for HashMap to simplify construction in simple single key/single value case -Deprecated MSVC11 support. |
||
#2 | 12508 | ShadauxCat |
-Added threading library. Currently only functional for Linux; Windows will fail to link. (I will fix this soon.) -Fixed missing move and copy constructors in List and ForwardList -Fixed broken move constructor in HashMap -Fixed missing const get() in HashMap -Fixed broken operator-> in ListIterator -Added sprawl::noncopyable -Added sketch headers for filesystem library -Made StringLiteral hashable, added special hashes for pointers and integers in murmur3 -Fixed compiler warning in async_network -Updated memory allocators to use new threading library for mutexes -Added accessibility to sprawl::StringLiteral to be able toa ccess its pointer and length and perform pointer comparisons #review-12504 |
||
#1 | 11496 | ShadauxCat | Initial checkin: Current states for csbuild and libSprawl |