~kiwec/ke

ke/src/Document.h -rw-r--r-- 3.4 KiB
1cc8481d — Wolf Clément Fix compilation 3 years ago
                                                                                
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
#pragma once
#include <assert.h>
#include <stdint.h>
#include "Syntax.h"

class Line;
using uint = uint32_t;

#pragma once
#include <cstdlib>
#include <cstring>
#include <memory>

template<typename T>
class Data {
protected:
	T* m_data;

	/// Number of allocated bytes
	uint m_alloc;

	/// Number of written elements (not bytes)
	/// not counting null terminator
	uint m_size;

	void expand(uint min_size) {
		// + 1 for null-terminating
		if(m_alloc >= (min_size + 1) * sizeof(T)) return;
		m_alloc = ((min_size + 1) * 1.5) * sizeof(T);
		m_data = (T*) realloc(m_data, m_alloc);
	}

public:
	Data() {
		m_alloc = 64 * sizeof(T);
		m_size = 0;
		m_data = (T*) malloc(m_alloc);

		// All Data types are null-terminated
		m_data[0] = 0;
	}

	~Data() {
		delete[] m_data;
	}

	T& operator[](uint pos) const {
		assert(pos <= m_size);
		return m_data[pos];
	}

	/// Erase the given range, from and to included
	/// erase(0, 1) would remove the first element
	void erase(uint start, uint size) {
		assert(start + size <= m_size);
		memmove(&m_data[start],
		        &m_data[start + size],
				(m_size - (start + size)) * sizeof(T));
		m_size -= size;

		// Rewrite null marker
		m_data[m_size] = 0;
	}

	/// Inserts the given data to the left of pos
	/// insert(x, xsize, 0) would insert at the start
	void insert(const T* inserted_data, uint data_size, uint pos) {
		assert(pos <= m_size);
		expand(m_size + data_size);

		auto old_pos = m_data + pos;
		auto new_pos = old_pos + data_size;
		auto moved_bytes = (m_size - pos) * sizeof(T);
		auto copied_bytes = data_size * sizeof(T);

		// Move existing data and insert new data
		memmove(new_pos, old_pos, moved_bytes);
		memcpy(old_pos, inserted_data, copied_bytes);

		// Update size of container
		m_size += data_size;

		// Rewrite null marker
		m_data[m_size] = 0;
	}

	uint size() {
		return m_size;
	}

	/// Return a copy of the requested range
	std::unique_ptr<T[]> copy(uint start, uint size) {
		assert(start + size <= m_size);
		std::unique_ptr<T[]> cpy(new T[size + 1]);
		memcpy(cpy, m_data + start, size);
		cpy[size] = 0;
		return cpy;
	}
};

class Text : public Data<wchar_t> {
	Data<syntax_t> m_syntax;

	/// Number of lines
	uint nb_lines = 1;

public:
	void erase(uint start, uint size) {
		assert(start + size <= m_size);

		// Update line count
		for(uint i = 0; i < size; i++) {
			if(m_data[start + i] == L'\n') {
				nb_lines--;
			}
		}

		// Erase data
		Data::erase(start, size);

		// Update syntax
		m_syntax.erase(start, size);
	}

	/// Find the line number of the given Line start
	Line find_line(wchar_t* pos);

	/// Returns the requested line
	/// line_number starts at 1
	Line get_line(uint line_number);

	Line get_line(Line closest, uint wanted_line_number);

	/// Returns the number of lines in the Document
	uint get_nb_lines();

	void insert(const wchar_t* inserted_data, uint data_size, uint pos) {
		assert(pos <= m_size);

		// Update line count
		for(uint i = 0; i < data_size; i++) {
			if(inserted_data[i] == L'\n') {
				nb_lines++;
			}
		}

		// Insert data
		Data::insert(inserted_data, data_size, pos);

		// Resize syntax
		auto zeroes = new syntax_t[data_size]();
		m_syntax.insert(zeroes, data_size, pos);
		delete[] zeroes;
		assert(m_syntax.size() == m_size);
	}

	/// Returns a <line, pos> pair if the string is found, <0, 0> otherwise
	std::pair<uint, uint> search(const wchar_t* str);

	syntax_t* syntax() { return &m_syntax[0]; }
};