File: utility.hpp

package info (click to toggle)
ares 126-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 32,600 kB
  • sloc: cpp: 356,508; ansic: 20,394; makefile: 16; sh: 2
file content (184 lines) | stat: -rw-r--r-- 4,701 bytes parent folder | download
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#pragma once

namespace nall {

inline auto string::read(string_view filename) -> string {
  #if !defined(_WIN32)
  FILE* fp = fopen(filename, "rb");
  #else
  FILE* fp = _wfopen(utf16_t(filename), L"rb");
  #endif

  string result;
  if(!fp) return result;

  fseek(fp, 0, SEEK_END);
  s32 filesize = ftell(fp);
  if(filesize < 0) return fclose(fp), result;

  rewind(fp);
  result.resize(filesize);
  (void)fread(result.get(), 1, filesize, fp);
  return fclose(fp), result;
}

inline auto string::repeat(string_view pattern, u32 times) -> string {
  string result;
  while(times--) result.append(pattern.data());
  return result;
}

inline auto string::fill(char fill) -> string& {
  memory::fill(get(), size(), fill);
  return *this;
}

inline auto string::hash() const -> u32 {
  const char* p = data();
  u32 length = size();
  u32 result = 5381;
  while(length--) result = (result << 5) + result + *p++;
  return result;
}

inline auto string::remove(u32 offset, u32 length) -> string& {
  char* p = get();
  length = min(length, size());
  memory::move(p + offset, p + offset + length, size() - length);
  return resize(size() - length);
}

inline auto string::reverse() -> string& {
  char* p = get();
  u32 length = size();
  u32 pivot = length >> 1;
  for(s32 x = 0, y = length - 1; x < pivot && y >= 0; x++, y--) std::swap(p[x], p[y]);
  return *this;
}

//+length => insert/delete from start (right justify)
//-length => insert/delete from end (left justify)
inline auto string::size(s32 length, char fill) -> string& {
  u32 size = this->size();
  if(size == length) return *this;

  bool right = length >= 0;
  length = abs(length);

  if(size < length) {  //expand
    resize(length);
    char* p = get();
    u32 displacement = length - size;
    if(right) memory::move(p + displacement, p, size);
    else p += size;
    while(displacement--) *p++ = fill;
  } else {  //shrink
    char* p = get();
    u32 displacement = size - length;
    if(right) memory::move(p, p + displacement, length);
    resize(length);
  }

  return *this;
}

inline auto slice(string_view self, s32 offset, s32 length) -> string {
  string result;
  if(offset < 0) offset = self.size() - abs(offset);
  if(offset >= 0 && offset < self.size()) {
    if(length < 0) length = self.size() - offset;
    if(length >= 0) {
      result.resize(length);
      memory::copy(result.get(), self.data() + offset, length);
    }
  }
  return result;
}

inline auto string::slice(s32 offset, s32 length) const -> string {
  return nall::slice(*this, offset, length);
}

template<typename T> inline auto fromInteger(char* result, T value) -> char* {
  bool negative = value < 0;
  if(!negative) value = -value;  //negate positive integers to support eg INT_MIN

  char buffer[1 + sizeof(T) * 3];
  u32 size = 0;

  do {
    s32 n = value % 10;  //-0 to -9
    buffer[size++] = '0' - n;  //'0' to '9'
    value /= 10;
  } while(value);
  if(negative) buffer[size++] = '-';

  for(s32 x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
  result[size] = 0;
  return result;
}

template<typename T> inline auto fromNatural(char* result, T value) -> char* {
  char buffer[1 + sizeof(T) * 3];
  u32 size = 0;

  do {
    u32 n = value % 10;
    buffer[size++] = '0' + n;
    value /= 10;
  } while(value);

  for(s32 x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
  result[size] = 0;
  return result;
}

template<typename T> inline auto fromHex(char* result, T value) -> char* {
  char buffer[1 + sizeof(T) * 2];
  u32 size = 0;

  do {
    u32 n = value & 15;
    if(n <= 9) {
      buffer[size++] = '0' + n;
    } else {
      buffer[size++] = 'a' + n - 10;
    }
    value >>= 4;
  } while(value);

  for(s32 x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
  result[size] = 0;
  return result;
}

//using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors.
template<typename T> inline auto fromReal(char* result, T value) -> u32 {
  char buffer[256];
  #ifdef _WIN32
  //Windows C-runtime does not support long double via sprintf()
  sprintf(buffer, "%f", (double)value);
  #else
  sprintf(buffer, "%Lf", (long double)value);
  #endif

  //remove excess 0's in fraction (2.500000 -> 2.5)
  for(char* p = buffer; *p; p++) {
    if(*p == '.') {
      char* p = buffer + strlen(buffer) - 1;
      while(*p == '0') {
        if(*(p - 1) != '.') *p = 0;  //... but not for eg 1.0 -> 1.
        p--;
      }
      break;
    }
  }

  u32 length = strlen(buffer);
  if(result) strcpy(result, buffer);
  return length + 1;
}

}