1 | //============================================================================ |
2 | // |
3 | // BBBBB SSSS PPPPP FFFFFF |
4 | // BB BB SS SS PP PP FF |
5 | // BB BB SS PP PP FF |
6 | // BBBBB SSSS PPPPP FFFF -- "Brad's Simple Portability Framework" |
7 | // BB BB SS PP FF |
8 | // BB BB SS SS PP FF |
9 | // BBBBB SSSS PP FF |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #ifndef BSPF_HXX |
19 | #define BSPF_HXX |
20 | |
21 | /** |
22 | This file defines various basic data types and preprocessor variables |
23 | that need to be defined for different operating systems. |
24 | |
25 | @author Bradford W. Mott and Stephen Anthony |
26 | */ |
27 | |
28 | #include <climits> |
29 | #include <cstdint> |
30 | // Types for 8/16/32/64-bit signed and unsigned integers |
31 | using Int8 = int8_t; |
32 | using uInt8 = uint8_t; |
33 | using Int16 = int16_t; |
34 | using uInt16 = uint16_t; |
35 | using Int32 = int32_t; |
36 | using uInt32 = uint32_t; |
37 | using Int64 = int64_t; |
38 | using uInt64 = uint64_t; |
39 | |
40 | // The following code should provide access to the standard C++ objects and |
41 | // types: cout, cerr, string, ostream, istream, etc. |
42 | #include <array> |
43 | #include <algorithm> |
44 | #include <iostream> |
45 | #include <fstream> |
46 | #include <iomanip> |
47 | #include <memory> |
48 | #include <string> |
49 | #include <sstream> |
50 | #include <cstring> |
51 | #include <cctype> |
52 | #include <cstdio> |
53 | #include <ctime> |
54 | #include <utility> |
55 | #include <vector> |
56 | |
57 | using std::cin; |
58 | using std::cout; |
59 | using std::cerr; |
60 | using std::endl; |
61 | using std::string; |
62 | using std::istream; |
63 | using std::ostream; |
64 | using std::fstream; |
65 | using std::iostream; |
66 | using std::ifstream; |
67 | using std::ofstream; |
68 | using std::ostringstream; |
69 | using std::istringstream; |
70 | using std::stringstream; |
71 | using std::unique_ptr; |
72 | using std::shared_ptr; |
73 | using std::make_unique; |
74 | using std::make_shared; |
75 | using std::array; |
76 | using std::vector; |
77 | using std::runtime_error; |
78 | |
79 | // Common array types |
80 | using IntArray = std::vector<Int32>; |
81 | using uIntArray = std::vector<uInt32>; |
82 | using BoolArray = std::vector<bool>; |
83 | using ByteArray = std::vector<uInt8>; |
84 | using ShortArray = std::vector<uInt16>; |
85 | using StringList = std::vector<std::string>; |
86 | using ByteBuffer = std::unique_ptr<uInt8[]>; |
87 | |
88 | // We use KB a lot; let's make a literal for it |
89 | constexpr uInt32 operator "" _KB(unsigned long long size) |
90 | { |
91 | return static_cast<uInt32>(size * 1024); |
92 | } |
93 | |
94 | static const string EmptyString("" ); |
95 | |
96 | // This is defined by some systems, but Stella has other uses for it |
97 | #undef PAGE_SIZE |
98 | #undef PAGE_MASK |
99 | |
100 | namespace BSPF |
101 | { |
102 | static constexpr float PI_f = 3.141592653589793238462643383279502884f; |
103 | static constexpr double PI_d = 3.141592653589793238462643383279502884; |
104 | |
105 | // CPU architecture type |
106 | // This isn't complete yet, but takes care of all the major platforms |
107 | #if defined(__i386__) || defined(_M_IX86) |
108 | static const string ARCH = "i386" ; |
109 | #elif defined(__x86_64__) || defined(_WIN64) |
110 | static const string ARCH = "x86_64" ; |
111 | #elif defined(__powerpc__) || defined(__ppc__) |
112 | static const string ARCH = "ppc" ; |
113 | #elif defined(__arm__) || defined(__thumb__) |
114 | static const string ARCH = "arm32" ; |
115 | #elif defined(__aarch64__) |
116 | static const string ARCH = "arm64" ; |
117 | #else |
118 | static const string ARCH = "NOARCH" ; |
119 | #endif |
120 | |
121 | // Combines 'max' and 'min', and clamps value to the upper/lower value |
122 | // if it is outside the specified range |
123 | template<class T> inline T clamp(T val, T lower, T upper) |
124 | { |
125 | return (val < lower) ? lower : (val > upper) ? upper : val; |
126 | } |
127 | template<class T> inline void clamp(T& val, T lower, T upper, T setVal) |
128 | { |
129 | if(val < lower || val > upper) val = setVal; |
130 | } |
131 | |
132 | // Convert string to given case |
133 | inline const string& toUpperCase(string& s) |
134 | { |
135 | transform(s.begin(), s.end(), s.begin(), ::toupper); |
136 | return s; |
137 | } |
138 | inline const string& toLowerCase(string& s) |
139 | { |
140 | transform(s.begin(), s.end(), s.begin(), ::tolower); |
141 | return s; |
142 | } |
143 | |
144 | // Compare two strings, ignoring case |
145 | inline int compareIgnoreCase(const string& s1, const string& s2) |
146 | { |
147 | #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__ |
148 | return _stricmp(s1.c_str(), s2.c_str()); |
149 | #else |
150 | return strcasecmp(s1.c_str(), s2.c_str()); |
151 | #endif |
152 | } |
153 | inline int compareIgnoreCase(const char* s1, const char* s2) |
154 | { |
155 | #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__ |
156 | return _stricmp(s1, s2); |
157 | #else |
158 | return strcasecmp(s1, s2); |
159 | #endif |
160 | } |
161 | |
162 | // Test whether the first string starts with the second one (case insensitive) |
163 | inline bool startsWithIgnoreCase(const string& s1, const string& s2) |
164 | { |
165 | #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__ |
166 | return _strnicmp(s1.c_str(), s2.c_str(), s2.length()) == 0; |
167 | #else |
168 | return strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0; |
169 | #endif |
170 | } |
171 | inline bool startsWithIgnoreCase(const char* s1, const char* s2) |
172 | { |
173 | #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__ |
174 | return _strnicmp(s1, s2, strlen(s2)) == 0; |
175 | #else |
176 | return strncasecmp(s1, s2, strlen(s2)) == 0; |
177 | #endif |
178 | } |
179 | |
180 | // Test whether two strings are equal (case insensitive) |
181 | inline bool equalsIgnoreCase(const string& s1, const string& s2) |
182 | { |
183 | return compareIgnoreCase(s1, s2) == 0; |
184 | } |
185 | |
186 | // Find location (if any) of the second string within the first, |
187 | // starting from 'startpos' in the first string |
188 | inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0) |
189 | { |
190 | auto pos = std::search(s1.cbegin()+startpos, s1.cend(), |
191 | s2.cbegin(), s2.cend(), [](char ch1, char ch2) { |
192 | return toupper(uInt8(ch1)) == toupper(uInt8(ch2)); |
193 | }); |
194 | return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos); |
195 | } |
196 | |
197 | // Test whether the first string ends with the second one (case insensitive) |
198 | inline bool endsWithIgnoreCase(const string& s1, const string& s2) |
199 | { |
200 | if(s1.length() >= s2.length()) |
201 | { |
202 | const char* end = s1.c_str() + s1.length() - s2.length(); |
203 | return compareIgnoreCase(end, s2.c_str()) == 0; |
204 | } |
205 | return false; |
206 | } |
207 | |
208 | // Test whether the first string contains the second one (case insensitive) |
209 | inline bool containsIgnoreCase(const string& s1, const string& s2) |
210 | { |
211 | return findIgnoreCase(s1, s2) != string::npos; |
212 | } |
213 | |
214 | // Test whether the first string matches the second one (case insensitive) |
215 | // - the first character must match |
216 | // - the following characters must appear in the order of the first string |
217 | inline bool matches(const string& s1, const string& s2) |
218 | { |
219 | if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1))) |
220 | { |
221 | size_t pos = 1; |
222 | for(uInt32 j = 1; j < s2.size(); ++j) |
223 | { |
224 | size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos); |
225 | if(found == string::npos) |
226 | return false; |
227 | pos += found + 1; |
228 | } |
229 | return true; |
230 | } |
231 | return false; |
232 | } |
233 | |
234 | // C++11 way to get local time |
235 | // Equivalent to the C-style localtime() function, but is thread-safe |
236 | inline std::tm localTime() |
237 | { |
238 | std::time_t currtime; |
239 | std::time(&currtime); |
240 | std::tm tm_snapshot; |
241 | #if (defined BSPF_WINDOWS || defined __WIN32__) && (!defined __GNUG__ || defined __MINGW32__) |
242 | localtime_s(&tm_snapshot, &currtime); |
243 | #else |
244 | localtime_r(&currtime, &tm_snapshot); |
245 | #endif |
246 | return tm_snapshot; |
247 | } |
248 | } // namespace BSPF |
249 | |
250 | #endif |
251 | |