1 /**
2  * Copyright (c) 2014, Timothy Stack
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  * * Neither the name of Timothy Stack nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * @file shared_buffer.hh
30  */
31 
32 #ifndef shared_buffer_hh
33 #define shared_buffer_hh
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 
39 #include <string>
40 #include <vector>
41 
42 #include "auto_mem.hh"
43 #include "base/lnav_log.hh"
44 
45 class shared_buffer;
46 
47 struct shared_buffer_ref {
48 public:
shared_buffer_refshared_buffer_ref49     shared_buffer_ref(char *data = nullptr, size_t len = 0)
50         : sb_owner(nullptr), sb_data(data), sb_length(len) {
51     };
52 
~shared_buffer_refshared_buffer_ref53     ~shared_buffer_ref() {
54         this->disown();
55     };
56 
shared_buffer_refshared_buffer_ref57     shared_buffer_ref(const shared_buffer_ref &other) {
58         this->sb_owner = nullptr;
59         this->sb_data = nullptr;
60         this->sb_length = 0;
61 
62         this->copy_ref(other);
63     };
64 
65     shared_buffer_ref(shared_buffer_ref &&other) noexcept;
66 
operator =shared_buffer_ref67     shared_buffer_ref &operator=(const shared_buffer_ref &other) {
68         if (this != &other) {
69             this->disown();
70             this->copy_ref(other);
71         }
72 
73         return *this;
74     };
75 
emptyshared_buffer_ref76     bool empty() const {
77         return this->sb_data == nullptr || this->sb_length == 0;
78     };
79 
get_datashared_buffer_ref80     const char *get_data() const { return this->sb_data; };
81 
get_data_atshared_buffer_ref82     const char *get_data_at(off_t offset) const {
83         return &this->sb_data[offset];
84     };
85 
lengthshared_buffer_ref86     size_t length() const { return this->sb_length; };
87 
rtrimshared_buffer_ref88     shared_buffer_ref &rtrim(bool pred(char)) {
89         while (this->sb_length > 0 && pred(this->sb_data[this->sb_length - 1])) {
90             this->sb_length -= 1;
91         }
92 
93         return *this;
94     }
95 
containsshared_buffer_ref96     bool contains(const char *ptr) const {
97         const char *buffer_end = this->sb_data + this->sb_length;
98 
99         return (this->sb_data <= ptr && ptr < buffer_end);
100     };
101 
get_writable_datashared_buffer_ref102     char *get_writable_data() {
103         if (this->take_ownership()) {
104             return this->sb_data;
105         }
106 
107         return nullptr;
108     };
109 
110     void share(shared_buffer &sb, char *data, size_t len);
111 
112     bool subset(shared_buffer_ref &other, off_t offset, size_t len);
113 
114     bool take_ownership();
115 
116     void disown();
117 
118 private:
119     void copy_ref(const shared_buffer_ref &other);
120 
121     auto_mem<char *> sb_backtrace;
122     shared_buffer *sb_owner;
123     char *sb_data;
124     size_t sb_length;
125 };
126 
127 class shared_buffer {
128 public:
~shared_buffer()129     ~shared_buffer() {
130         this->invalidate_refs();
131     }
132 
add_ref(shared_buffer_ref & ref)133     void add_ref(shared_buffer_ref &ref) {
134         this->sb_refs.push_back(&ref);
135     };
136 
invalidate_refs()137     bool invalidate_refs() {
138         bool retval = true;
139 
140         while (!this->sb_refs.empty()) {
141             auto iter = this->sb_refs.begin();
142 
143             retval = retval && (*iter)->take_ownership();
144         }
145 
146         return retval;
147     };
148 
149     std::vector<shared_buffer_ref*> sb_refs;
150 };
151 
152 struct tmp_shared_buffer {
tmp_shared_buffertmp_shared_buffer153     explicit tmp_shared_buffer(const char *str, size_t len = -1) {
154         if (len == (size_t)-1) {
155             len = strlen(str);
156         }
157 
158         this->tsb_ref.share(this->tsb_manager, (char *)str, len);
159     };
160 
161     shared_buffer tsb_manager;
162     shared_buffer_ref tsb_ref;
163 };
164 
to_string(const shared_buffer_ref & sbr)165 inline std::string to_string(const shared_buffer_ref &sbr)
166 {
167     return {sbr.get_data(), sbr.length()};
168 }
169 
170 #endif
171