1 /*
2  * misc_util.h
3  * -----------
4  * Purpose: Various useful utility functions.
5  * Notes  : (currently none)
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #pragma once
12 
13 #include "openmpt/all/BuildSettings.hpp"
14 
15 #include "mpt/base/span.hpp"
16 #include "mpt/exception_text/exception_text.hpp"
17 
18 #include "mptAssert.h"
19 #include "mptBaseMacros.h"
20 #include "mptBaseTypes.h"
21 #include "mptBaseUtils.h"
22 #include "mptString.h"
23 
24 // old
25 #include "mptBaseUtils.h"
26 #include "mptStringFormat.h"
27 #include "mptStringParse.h"
28 #include "mptTime.h"
29 
30 #include <stdexcept>
31 #include <optional>
32 #include <vector>
33 
34 #include <cstdlib>
35 
36 #include <stdlib.h>
37 
38 
39 
40 OPENMPT_NAMESPACE_BEGIN
41 
42 
43 
44 namespace Util
45 {
46 
47 
48 
49 	// Insert a range of items [insStart,  insEnd], and possibly shift item fix to the left.
50 	template<typename T>
InsertItem(const T insStart,const T insEnd,T & fix)51 	void InsertItem(const T insStart, const T insEnd, T &fix)
52 	{
53 		MPT_ASSERT(insEnd >= insStart);
54 		if(fix >= insStart)
55 		{
56 			fix += (insEnd - insStart + 1);
57 		}
58 	}
59 
60 	// Insert a range of items [insStart,  insEnd], and possibly shift items in range [fixStart, fixEnd] to the right.
61 	template<typename T>
InsertRange(const T insStart,const T insEnd,T & fixStart,T & fixEnd)62 	void InsertRange(const T insStart, const T insEnd, T &fixStart, T &fixEnd)
63 	{
64 		MPT_ASSERT(insEnd >= insStart);
65 		const T insLength = insEnd - insStart + 1;
66 		if(fixStart >= insEnd)
67 		{
68 			fixStart += insLength;
69 		}
70 		if(fixEnd >= insEnd)
71 		{
72 			fixEnd += insLength;
73 		}
74 	}
75 
76 	// Delete a range of items [delStart,  delEnd], and possibly shift item fix to the left.
77 	template<typename T>
DeleteItem(const T delStart,const T delEnd,T & fix)78 	void DeleteItem(const T delStart, const T delEnd, T &fix)
79 	{
80 		MPT_ASSERT(delEnd >= delStart);
81 		if(fix > delEnd)
82 		{
83 			fix -= (delEnd - delStart + 1);
84 		}
85 	}
86 
87 	// Delete a range of items [delStart,  delEnd], and possibly shift items in range [fixStart, fixEnd] to the left.
88 	template<typename T>
DeleteRange(const T delStart,const T delEnd,T & fixStart,T & fixEnd)89 	void DeleteRange(const T delStart, const T delEnd, T &fixStart, T &fixEnd)
90 	{
91 		MPT_ASSERT(delEnd >= delStart);
92 		const T delLength = delEnd - delStart + 1;
93 		if(delStart < fixStart  && delEnd < fixStart)
94 		{
95 			// cut part is before loop start
96 			fixStart -= delLength;
97 			fixEnd -= delLength;
98 		} else if(delStart < fixStart  && delEnd < fixEnd)
99 		{
100 			// cut part is partly before loop start
101 			fixStart = delStart;
102 			fixEnd -= delLength;
103 		} else if(delStart >= fixStart && delEnd < fixEnd)
104 		{
105 			// cut part is in the loop
106 			fixEnd -= delLength;
107 		} else if(delStart >= fixStart && delStart < fixEnd && delEnd > fixEnd)
108 		{
109 			// cut part is partly before loop end
110 			fixEnd = delStart;
111 		}
112 	}
113 
114 
115 
116 	template<typename T, std::size_t n>
117 	class fixed_size_queue
118 	{
119 	private:
120 		T buffer[n+1];
121 		std::size_t read_position;
122 		std::size_t write_position;
123 	public:
fixed_size_queue()124 		fixed_size_queue() : read_position(0), write_position(0)
125 		{
126 			return;
127 		}
clear()128 		void clear()
129 		{
130 			read_position = 0;
131 			write_position = 0;
132 		}
read_size()133 		std::size_t read_size() const
134 		{
135 			if ( write_position > read_position )
136 			{
137 				return write_position - read_position;
138 			} else if ( write_position < read_position )
139 			{
140 				return write_position - read_position + n + 1;
141 			} else
142 			{
143 				return 0;
144 			}
145 		}
write_size()146 		std::size_t write_size() const
147 		{
148 			if ( write_position > read_position )
149 			{
150 				return read_position - write_position + n;
151 			} else if ( write_position < read_position )
152 			{
153 				return read_position - write_position - 1;
154 			} else
155 			{
156 				return n;
157 			}
158 		}
push(const T & v)159 		bool push( const T & v )
160 		{
161 			if ( !write_size() )
162 			{
163 				return false;
164 			}
165 			buffer[write_position] = v;
166 			write_position = ( write_position + 1 ) % ( n + 1 );
167 			return true;
168 		}
pop()169 		bool pop() {
170 			if ( !read_size() )
171 			{
172 				return false;
173 			}
174 			read_position = ( read_position + 1 ) % ( n + 1 );
175 			return true;
176 		}
peek()177 		T peek() {
178 			if ( !read_size() )
179 			{
180 				return T();
181 			}
182 			return buffer[read_position];
183 		}
peek_p()184 		const T * peek_p()
185 		{
186 			if ( !read_size() )
187 			{
188 				return nullptr;
189 			}
190 			return &(buffer[read_position]);
191 		}
peek_next_p()192 		const T * peek_next_p()
193 		{
194 			if ( read_size() < 2 )
195 			{
196 				return nullptr;
197 			}
198 			return &(buffer[(read_position+1)%(n+1)]);
199 		}
200 	};
201 
202 
203 
204 } // namespace Util
205 
206 
207 
208 #if MPT_OS_WINDOWS
209 
210 template <typename Tstring, typename Tbuf, typename Tsize>
ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(const Tbuf * buf,Tsize sizeBytes)211 Tstring ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(const Tbuf *buf, Tsize sizeBytes)
212 {
213 	// REG_SZ may contain a single NUL terminator, multiple NUL terminators, or no NUL terminator at all
214 	return Tstring(reinterpret_cast<const typename Tstring::value_type*>(buf), reinterpret_cast<const typename Tstring::value_type*>(buf) + (sizeBytes / sizeof(typename Tstring::value_type))).c_str();
215 }
216 
217 
218 #endif // MPT_OS_WINDOWS
219 
220 
221 OPENMPT_NAMESPACE_END
222