Skip to content

Commit d423c3b

Browse files
committed
Simpler typedef
1 parent ba97461 commit d423c3b

File tree

8 files changed

+92
-141
lines changed

8 files changed

+92
-141
lines changed

_parts/part1.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,11 @@ int main(int argc, char* argv[]) {
8383
8484
We'll define `InputBuffer` as a small wrapper around the state we need to store to interact with [getline()](http://man7.org/linux/man-pages/man3/getline.3.html). (More on that in a minute)
8585
```c
86-
struct InputBuffer_t {
86+
typedef struct {
8787
char* buffer;
8888
size_t buffer_length;
8989
ssize_t input_length;
90-
};
91-
typedef struct InputBuffer_t InputBuffer;
90+
} InputBuffer;
9291
9392
InputBuffer* new_input_buffer() {
9493
InputBuffer* input_buffer = malloc(sizeof(InputBuffer));
@@ -178,12 +177,11 @@ Alright, we've got a working REPL. In the next part, we'll start developing our
178177
#include <stdlib.h>
179178
#include <string.h>
180179

181-
struct InputBuffer_t {
180+
typedef struct {
182181
char* buffer;
183182
size_t buffer_length;
184183
ssize_t input_length;
185-
};
186-
typedef struct InputBuffer_t InputBuffer;
184+
} InputBuffer;
187185

188186
InputBuffer* new_input_buffer() {
189187
InputBuffer* input_buffer = malloc(sizeof(InputBuffer));

_parts/part2.md

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,12 @@ Lastly, we pass the prepared statement to `execute_statement`. This function wil
6161
Notice that two of our new functions return enums indicating success or failure:
6262

6363
```c
64-
enum MetaCommandResult_t {
64+
typedef enum {
6565
META_COMMAND_SUCCESS,
6666
META_COMMAND_UNRECOGNIZED_COMMAND
67-
};
68-
typedef enum MetaCommandResult_t MetaCommandResult;
67+
} MetaCommandResult;
6968

70-
enum PrepareResult_t { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT };
71-
typedef enum PrepareResult_t PrepareResult;
69+
typedef enum { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT } PrepareResult;
7270
```
7371
7472
"Unrecognized statement"? That seems a bit like an exception. But [exceptions are bad](https://www.youtube.com/watch?v=EVhCUSgNbzo) (and C doesn't even support them), so I'm using enum result codes wherever practical. The C compiler will complain if my switch statement doesn't handle a member of the enum, so we can feel a little more confident we handle every result of a function. Expect more result codes to be added in the future.
@@ -88,13 +86,11 @@ MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
8886
Our "prepared statement" right now just contains an enum with two possible values. It will contain more data as we allow parameters in statements:
8987

9088
```c
91-
enum StatementType_t { STATEMENT_INSERT, STATEMENT_SELECT };
92-
typedef enum StatementType_t StatementType;
89+
typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;
9390

94-
struct Statement_t {
91+
typedef struct {
9592
StatementType type;
96-
};
97-
typedef struct Statement_t Statement;
93+
} Statement;
9894
```
9995

10096
`prepare_statement` (our "SQL Compiler") does not understand SQL right now. In fact, it only understands two words:
@@ -153,25 +149,20 @@ The skeleton of our database is taking shape... wouldn't it be nice if it stored
153149

154150
```diff
155151
@@ -10,6 +10,23 @@ struct InputBuffer_t {
156-
};
157-
typedef struct InputBuffer_t InputBuffer;
152+
} InputBuffer;
158153

159-
+enum MetaCommandResult_t {
154+
+typedef enum {
160155
+ META_COMMAND_SUCCESS,
161156
+ META_COMMAND_UNRECOGNIZED_COMMAND
162-
+};
163-
+typedef enum MetaCommandResult_t MetaCommandResult;
157+
+} MetaCommandResult;
164158
+
165-
+enum PrepareResult_t { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT };
166-
+typedef enum PrepareResult_t PrepareResult;
159+
+typedef enum { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT } PrepareResult;
167160
+
168-
+enum StatementType_t { STATEMENT_INSERT, STATEMENT_SELECT };
169-
+typedef enum StatementType_t StatementType;
161+
+typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;
170162
+
171-
+struct Statement_t {
163+
+typedef struct {
172164
+ StatementType type;
173-
+};
174-
+typedef struct Statement_t Statement;
165+
+} Statement;
175166
+
176167
InputBuffer* new_input_buffer() {
177168
InputBuffer* input_buffer = malloc(sizeof(InputBuffer));

_parts/part3.md

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,16 @@ We store those parsed arguments into a new `Row` data structure inside the state
4646
```diff
4747
+#define COLUMN_USERNAME_SIZE 32
4848
+#define COLUMN_EMAIL_SIZE 255
49-
+struct Row_t {
49+
+typedef struct {
5050
+ uint32_t id;
5151
+ char username[COLUMN_USERNAME_SIZE];
5252
+ char email[COLUMN_EMAIL_SIZE];
53-
+};
54-
+typedef struct Row_t Row;
53+
+} Row;
5554
+
56-
struct Statement_t {
55+
typedef struct {
5756
StatementType type;
5857
+ Row row_to_insert; // only used by insert statement
59-
};
60-
typedef struct Statement_t Statement;
58+
} Statement;
6159
```
6260

6361
Now we need to copy that data into some data structure representing the table. SQLite uses a B-tree for fast lookups, inserts and deletes. We'll start with something simpler. Like a B-tree, it will group rows into pages, but instead of arranging those pages as a tree it will arrange them as an array.
@@ -114,11 +112,10 @@ Next, a `Table` structure that points to pages of rows and keeps track of how ma
114112
+const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
115113
+const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;
116114
+
117-
+struct Table_t {
115+
+typedef struct {
118116
+ uint32_t num_rows;
119117
+ void* pages[TABLE_MAX_PAGES];
120-
+};
121-
+typedef struct Table_t Table;
118+
+} Table;
122119
```
123120

124121
I'm making our page size 4 kilobytes because it's the same size as a page used in the virtual memory systems of most computer architectures. This means one page in our database corresponds to one page used by the operating system. The operating system will move pages in and out of memory as whole units instead of breaking them up.
@@ -263,45 +260,38 @@ We'll address those issues in the next part. For now, here's the complete diff f
263260
#include <string.h>
264261
+#include <stdint.h>
265262

266-
struct InputBuffer_t {
263+
typedef struct {
267264
char* buffer;
268-
@@ -10,6 +11,105 @@ struct InputBuffer_t {
269-
};
270-
typedef struct InputBuffer_t InputBuffer;
265+
@@ -10,6 +11,105 @@ typedef struct {
266+
} InputBuffer;
271267

272-
+enum ExecuteResult_t { EXECUTE_SUCCESS, EXECUTE_TABLE_FULL };
273-
+typedef enum ExecuteResult_t ExecuteResult;
268+
+typedef enum { EXECUTE_SUCCESS, EXECUTE_TABLE_FULL } ExecuteResult;
274269
+
275-
+enum MetaCommandResult_t {
270+
+typedef enum {
276271
+ META_COMMAND_SUCCESS,
277272
+ META_COMMAND_UNRECOGNIZED_COMMAND
278-
+};
279-
+typedef enum MetaCommandResult_t MetaCommandResult;
273+
+} MetaCommandResult;
280274
+
281-
+enum PrepareResult_t {
275+
+typedef enum {
282276
+ PREPARE_SUCCESS,
283277
+ PREPARE_SYNTAX_ERROR,
284278
+ PREPARE_UNRECOGNIZED_STATEMENT
285-
+ };
286-
+typedef enum PrepareResult_t PrepareResult;
279+
+ } PrepareResult;
287280
+
288-
+enum StatementType_t { STATEMENT_INSERT, STATEMENT_SELECT };
289-
+typedef enum StatementType_t StatementType;
281+
+typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;
290282
+
291283
+#define COLUMN_USERNAME_SIZE 32
292284
+#define COLUMN_EMAIL_SIZE 255
293-
+struct Row_t {
285+
+typedef struct {
294286
+ uint32_t id;
295287
+ char username[COLUMN_USERNAME_SIZE];
296288
+ char email[COLUMN_EMAIL_SIZE];
297-
+};
298-
+typedef struct Row_t Row;
289+
+} Row;
299290
+
300-
+struct Statement_t {
291+
+typedef struct {
301292
+ StatementType type;
302293
+ Row row_to_insert; //only used by insert statement
303-
+};
304-
+typedef struct Statement_t Statement;
294+
+} Statement;
305295
+
306296
+#define size_of_attribute(Struct, Attribute) sizeof(((Struct*)0)->Attribute)
307297
+
@@ -318,11 +308,10 @@ We'll address those issues in the next part. For now, here's the complete diff f
318308
+const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
319309
+const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;
320310
+
321-
+struct Table_t {
311+
+typedef struct {
322312
+ uint32_t num_rows;
323313
+ void* pages[TABLE_MAX_PAGES];
324-
+};
325-
+typedef struct Table_t Table;
314+
+} Table;
326315
+
327316
+void print_row(Row* row) {
328317
+ printf("(%d, %s, %s)\n", row->id, row->username, row->email);

_parts/part4.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,13 @@ db >
121121
What's going on? If you take a look at our definition of a Row, we allocate exactly 32 bytes for username and exactly 255 bytes for email. But [C strings](http://www.cprogramming.com/tutorial/c/lesson9.html) are supposed to end with a null character, which we didn't allocate space for. The solution is to allocate one additional byte:
122122
```diff
123123
const uint32_t COLUMN_EMAIL_SIZE = 255;
124-
struct Row_t {
124+
typedef struct {
125125
uint32_t id;
126126
- char username[COLUMN_USERNAME_SIZE];
127127
- char email[COLUMN_EMAIL_SIZE];
128128
+ char username[COLUMN_USERNAME_SIZE + 1];
129129
+ char email[COLUMN_EMAIL_SIZE + 1];
130-
};
131-
typedef struct Row_t Row;
130+
} Row;
132131
```
133132

134133
And indeed that fixes it:
@@ -305,7 +304,7 @@ It's gonna be great.
305304

306305
Here's the complete diff for this part:
307306
```diff
308-
@@ -22,6 +22,8 @@ typedef enum MetaCommandResult_t MetaCommandResult;
307+
@@ -22,6 +22,8 @@
309308

310309
enum PrepareResult_t {
311310
PREPARE_SUCCESS,
@@ -314,16 +313,15 @@ Here's the complete diff for this part:
314313
PREPARE_SYNTAX_ERROR,
315314
PREPARE_UNRECOGNIZED_STATEMENT
316315
};
317-
@@ -34,8 +36,8 @@ typedef enum StatementType_t StatementType;
316+
@@ -34,8 +36,8 @@
318317
#define COLUMN_EMAIL_SIZE 255
319-
struct Row_t {
318+
typedef struct {
320319
uint32_t id;
321320
- char username[COLUMN_USERNAME_SIZE];
322321
- char email[COLUMN_EMAIL_SIZE];
323322
+ char username[COLUMN_USERNAME_SIZE + 1];
324323
+ char email[COLUMN_EMAIL_SIZE + 1];
325-
};
326-
typedef struct Row_t Row;
324+
} Row;
327325

328326
@@ -150,18 +152,40 @@ MetaCommandResult do_meta_command(InputBuffer* input_buffer, Table *table) {
329327
}

_parts/part5.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,17 @@ To make this easier, we're going to make an abstraction called the pager. We ask
4040
The Pager accesses the page cache and the file. The Table object makes requests for pages through the pager:
4141

4242
```diff
43-
+struct Pager_t {
43+
+typedef struct {
4444
+ int file_descriptor;
4545
+ uint32_t file_length;
4646
+ void* pages[TABLE_MAX_PAGES];
47-
+};
48-
+typedef struct Pager_t Pager;
47+
+} Pager;
4948
+
50-
struct Table_t {
49+
typedef struct {
5150
- void* pages[TABLE_MAX_PAGES];
5251
+ Pager* pager;
5352
uint32_t num_rows;
54-
};
53+
} Table;
5554
```
5655

5756
I'm renaming `new_table()` to `db_open()` because it now has the effect of opening a connection to the database. By opening a connection, I mean:
@@ -336,19 +335,17 @@ Until then!
336335
const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
337336
const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;
338337

339-
+struct Pager_t {
338+
+typedef struct {
340339
+ int file_descriptor;
341340
+ uint32_t file_length;
342341
+ void* pages[TABLE_MAX_PAGES];
343-
+};
344-
+typedef struct Pager_t Pager;
342+
+} Pager;
345343
+
346-
struct Table_t {
344+
typedef struct {
347345
uint32_t num_rows;
348346
- void* pages[TABLE_MAX_PAGES];
349347
+ Pager* pager;
350-
};
351-
typedef struct Table_t Table;
348+
} Table;
352349

353350
@@ -84,32 +94,81 @@ void deserialize_row(void *source, Row* destination) {
354351
memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);

_parts/part6.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ Those are the behaviors we're going to implement now. Later, we will also want t
2121
Without further ado, here's the `Cursor` type:
2222

2323
```diff
24-
+struct Cursor_t {
24+
+typedef struct {
2525
+ Table* table;
2626
+ uint32_t row_num;
2727
+ bool end_of_table; // Indicates a position one past the last element
28-
+};
29-
+typedef struct Cursor_t Cursor;
28+
+} Cursor;
3029
```
3130

3231
Given our current table data structure, all you need to identify a location in a table is the row number.
@@ -124,16 +123,14 @@ Alright, that's it! Like I said, this was a shorter refactor that should help us
124123

125124
Here's the complete diff to this part:
126125
```diff
127-
@@ -78,6 +78,13 @@ struct Table_t {
128-
};
129-
typedef struct Table_t Table;
126+
@@ -78,6 +78,13 @@ struct {
127+
} Table;
130128

131-
+struct Cursor_t {
129+
+typedef struct {
132130
+ Table* table;
133131
+ uint32_t row_num;
134132
+ bool end_of_table; // Indicates a position one past the last element
135-
+};
136-
+typedef struct Cursor_t Cursor;
133+
+} Cursor;
137134
+
138135
void print_row(Row* row) {
139136
printf("(%d, %s, %s)\n", row->id, row->username, row->email);

0 commit comments

Comments
 (0)