-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathobjects.h
150 lines (124 loc) · 4.49 KB
/
objects.h
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
#pragma once
#include <inttypes.h>
#if defined(NDEBUG)
#define CHECK
#else
#define CHECK(cond, msg) \
do { \
if (!(cond)) { \
fprintf(stderr, "Check failed: %s:%d, %s: %s\n", __FILE__, __LINE__, \
#cond, msg); \
abort(); \
} \
} while (0)
#endif
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef intptr_t word;
typedef uintptr_t uword;
typedef enum {
kInt,
kStr,
} ObjectType;
struct Object;
typedef struct Object Object;
typedef struct {
ObjectType type;
union {
const char* str_value;
};
} HeapObject;
// These constants are defined in a enum because the right hand side of a
// statement like
// static const int kFoo = ...;
// must be a so-called "Integer Constant Expression". Compilers are required to
// support a certain set of these expressions, but are not required to support
// arbitrary arithmetic with other integer constants. Compilers such as gcc
// before gcc-8 just decided not to play this game, while gcc-8+ and Clang play
// just fine.
// Since this arithmetic with constant values works just fine for enums, make
// all these constants enum values instead.
// See https://twitter.com/tekknolagi/status/1328449329472835586 for more info.
enum {
kBitsPerByte = 8, // bits
kWordSize = sizeof(word), // bytes
kBitsPerWord = kWordSize * kBitsPerByte, // bits
kIntegerTag = 0x0, // 0b0
kIntegerTagMask = 0x1, // 0b1
kIntegerShift = 1,
kIntegerBits = kBitsPerWord - kIntegerShift,
kHeapObjectTag = 0x1, // 0b01
kHeapObjectTagMask = 0x1, // 0b01
};
// These are defined as macros because they will not work as static const int
// constants (per above explanation), and enum constants are only required to
// be an int wide (per ISO C).
#define INTEGER_MAX ((1LL << (kIntegerBits - 1)) - 1)
#define INTEGER_MIN (-(1LL << (kIntegerBits - 1)))
bool object_is_int(Object* obj) {
return ((uword)obj & kIntegerTagMask) == kIntegerTag;
}
bool object_is_heap_object(Object* obj) {
return ((uword)obj & kHeapObjectTagMask) == kHeapObjectTag;
}
HeapObject* object_address(Object* obj) {
CHECK(object_is_heap_object(obj), "expected heap object");
return (HeapObject*)((uword)obj - kHeapObjectTag);
}
void object_free(Object* obj) {
CHECK(object_is_heap_object(obj), "expected heap object");
free(object_address(obj));
}
Object* object_from_address(HeapObject* obj) {
return (Object*)((uword)obj + kHeapObjectTag);
}
ObjectType object_type(Object* obj) {
if (object_is_int(obj)) {
return kInt;
}
return object_address(obj)->type;
}
bool object_is_str(Object* obj) { return object_type(obj) == kStr; }
word object_as_int(Object* obj) {
CHECK(object_is_int(obj), "expected int");
return (word)obj >> kIntegerShift;
}
const char* object_as_str(Object* obj) {
CHECK(object_is_str(obj), "expected str");
return object_address(obj)->str_value;
}
Object* new_int(word value) {
CHECK(value < INTEGER_MAX, "too big");
CHECK(value > INTEGER_MIN, "too small");
return (Object*)((uword)value << kIntegerShift);
}
Object* new_str(const char* value) {
HeapObject* result = (HeapObject*)malloc(sizeof *result);
CHECK(result != NULL, "could not allocate object");
*result = (HeapObject){.type = kStr, .str_value = value};
return object_from_address(result);
}
Object* int_add(Object* left, Object* right) {
CHECK(object_is_int(left), "expected int");
CHECK(object_is_int(right), "expected int");
return new_int(object_as_int(left) + object_as_int(right));
}
Object* int_print(Object* obj) {
CHECK(object_is_int(obj), "expected int");
fprintf(stderr, "int: %ld\n", object_as_int(obj));
return obj;
}
Object* str_add(Object* left, Object* right) {
CHECK(object_is_str(left), "expected str");
CHECK(object_is_str(right), "expected str");
word result_size =
strlen(object_as_str(left)) + strlen(object_as_str(right)) + 1;
char* result = (char*)malloc(result_size);
strcpy(result, object_as_str(left));
strcat(result, object_as_str(right));
return new_str(result);
}
Object* str_print(Object* obj) {
CHECK(object_is_str(obj), "expected str");
fprintf(stderr, "str: \"%s\"\n", object_as_str(obj));
return obj;
}