summaryrefslogtreecommitdiff
path: root/include/internal/catch_stringref.h
blob: 64f595b3682964cb15acf773b1fbceb105aa0edf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 *  Copyright 2016 Two Blue Cubes Ltd. All rights reserved.
 *
 *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 */
#ifndef CATCH_STRINGREF_H_INCLUDED
#define CATCH_STRINGREF_H_INCLUDED

#include <cstddef>
#include <string>
#include <iosfwd>

namespace Catch {

    /// A non-owning string class (similar to the forthcoming std::string_view)
    /// Note that, because a StringRef may be a substring of another string,
    /// it may not be null terminated. c_str() must return a null terminated
    /// string, however, and so the StringRef will internally take ownership
    /// (taking a copy), if necessary. In theory this ownership is not externally
    /// visible - but it does mean (substring) StringRefs should not be shared between
    /// threads.
    class StringRef {
    public:
        using size_type = std::size_t;

    private:
        friend struct StringRefTestAccess;

        char const* m_start;
        size_type m_size;

        char* m_data = nullptr;

        void takeOwnership();

        static constexpr char const* const s_empty = "";

    public: // construction/ assignment
        StringRef() noexcept
        :   StringRef( s_empty, 0 )
        {}

        StringRef( StringRef const& other ) noexcept
        :   m_start( other.m_start ),
            m_size( other.m_size )
        {}

        StringRef( StringRef&& other ) noexcept
        :   m_start( other.m_start ),
            m_size( other.m_size ),
            m_data( other.m_data )
        {
            other.m_data = nullptr;
        }

        StringRef( char const* rawChars ) noexcept;

        StringRef( char const* rawChars, size_type size ) noexcept
        :   m_start( rawChars ),
            m_size( size )
        {}

        StringRef( std::string const& stdString ) noexcept
        :   m_start( stdString.c_str() ),
            m_size( stdString.size() )
        {}

        ~StringRef() noexcept {
            delete[] m_data;
        }

        auto operator = ( StringRef const &other ) noexcept -> StringRef& {
            delete[] m_data;
            m_data = nullptr;
            m_start = other.m_start;
            m_size = other.m_size;
            return *this;
        }

        operator std::string() const;

        void swap( StringRef& other ) noexcept;

    public: // operators
        auto operator == ( StringRef const& other ) const noexcept -> bool;
        auto operator != ( StringRef const& other ) const noexcept -> bool;

        auto operator[] ( size_type index ) const noexcept -> char;

    public: // named queries
        auto empty() const noexcept -> bool {
            return m_size == 0;
        }
        auto size() const noexcept -> size_type {
            return m_size;
        }

        auto numberOfCharacters() const noexcept -> size_type;
        auto c_str() const -> char const*;

    public: // substrings and searches
        auto substr( size_type start, size_type size ) const noexcept -> StringRef;

        // Returns the current start pointer.
        // Note that the pointer can change when if the StringRef is a substring
        auto currentData() const noexcept -> char const*;

    private: // ownership queries - may not be consistent between calls
        auto isOwned() const noexcept -> bool;
        auto isSubstring() const noexcept -> bool;
    };

    auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
    auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
    auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;

    auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
    auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;


    inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
        return StringRef( rawChars, size );
    }

} // namespace Catch

inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
    return Catch::StringRef( rawChars, size );
}

#endif // CATCH_STRINGREF_H_INCLUDED