-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsymbol.h
342 lines (317 loc) · 13.4 KB
/
symbol.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
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#ifndef RBIMPL_SYMBOL_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_SYMBOL_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #rb_intern
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#include "ruby/internal/attr/noalias.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/constant_p.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/has/builtin.h"
#include "ruby/internal/value.h"
#define RB_ID2SYM rb_id2sym /**< @alias{rb_id2sym} */
#define RB_SYM2ID rb_sym2id /**< @alias{rb_sym2id} */
#define ID2SYM RB_ID2SYM /**< @old{RB_ID2SYM} */
#define SYM2ID RB_SYM2ID /**< @old{RB_SYM2ID} */
#define CONST_ID_CACHE RUBY_CONST_ID_CACHE /**< @old{RUBY_CONST_ID_CACHE} */
#define CONST_ID RUBY_CONST_ID /**< @old{RUBY_CONST_ID} */
/** @cond INTERNAL_MACRO */
#define rb_intern_const rb_intern_const
/** @endcond */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts an instance of ::rb_cSymbol into an ::ID.
*
* @param[in] obj An instance of ::rb_cSymbol.
* @exception rb_eTypeError `obj` is not an instance of ::rb_cSymbol.
* @return An ::ID of the identical symbol.
*/
ID rb_sym2id(VALUE obj);
/**
* Allocates an instance of ::rb_cSymbol that has the given id.
*
* @param[in] id An id.
* @retval RUBY_Qfalse No such id ever existed in the history.
* @retval Otherwise An allocated ::rb_cSymbol instance.
*/
VALUE rb_id2sym(ID id);
RBIMPL_ATTR_NONNULL(())
/**
* Finds or creates a symbol of the given name.
*
* @param[in] name The name of the id.
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given name.
* @note These days Ruby internally has two kinds of symbols (static /
* dynamic). Symbols created using this function would become a
* static one; i.e. would never be garbage collected. It is up to
* you to avoid memory leaks. Think twice before using it.
*/
ID rb_intern(const char *name);
/**
* Identical to rb_intern(), except it additionally takes the length of the
* string. This way you can have a symbol that contains NUL characters.
*
* @param[in] name The name of the id.
* @param[in] len Length of `name`.
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given name.
* @note These days Ruby internally has two kinds of symbols
* (static/dynamic). Symbols created using this function would
* become static ones; i.e. would never be garbage collected. It
* is up to you to avoid memory leaks. Think twice before using
* it.
*/
ID rb_intern2(const char *name, long len);
/**
* Identical to rb_intern(), except it takes an instance of ::rb_cString.
*
* @param[in] str The name of the id.
* @pre `str` must either be an instance of ::rb_cSymbol, or an instance
* of ::rb_cString, or responds to `#to_str` method.
* @exception rb_eTypeError Can't convert `str` into ::rb_cString.
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given str.
* @note These days Ruby internally has two kinds of symbols
* (static/dynamic). Symbols created using this function would
* become static ones; i.e. would never be garbage collected. It
* is up to you to avoid memory leaks. Think twice before using
* it.
*/
ID rb_intern_str(VALUE str);
/**
* Retrieves the name mapped to the given id.
*
* @param[in] id An id to query.
* @retval NULL Unknown id.
* @retval otherwise A name that the id represents.
* @note The return value is managed by the interpreter. Don't pass it
* to free().
* @note The underlying name can contain internal NUL bytes, so the return
* value might be a truncated representation due to the nature of C
* strings.
* @note This C string is backed by an underlying Ruby string. The Ruby
* string may move during GC compaction which would make this
* C string point to invalid memory. Do not use the return value
* of this function after a potential GC entry point.
*/
const char *rb_id2name(ID id);
RBIMPL_ATTR_NONNULL(())
/**
* Detects if the given name is already interned or not. It first tries to
* convert the argument to an instance of ::rb_cString if it is neither an
* instance of ::rb_cString nor ::rb_cSymbol. The conversion result is written
* back to the variable. Then queries if that name was already interned
* before. If found it returns such id, otherwise zero.
*
* We eventually introduced this API to avoid inadvertent symbol pin-down.
* Before, there was no way to know if an ID was already interned or not
* without actually creating one (== leaking memory). By using this API you
* can avoid such situations:
*
* ```CXX
* bool does_interning_this_leak_memory(VALUE obj)
* {
* auto tmp = obj;
* if (auto id = rb_check_id(&tmp); id) {
* return false;
* }
* else {
* return true; // Let GC sweep tmp if necessary.
* }
* }
* ```
*
* @param[in,out] namep A pointer to a name to query.
* @pre The object referred by `*namep` must either be an instance
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
* @exception rb_eEncodingError Given string is non-ASCII.
* @retval 0 No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
* @see https://bugs.ruby-lang.org/issues/5072
*
* @internal
*
* @shyouhei doesn't know why this has to raise rb_eEncodingError.
*/
ID rb_check_id(volatile VALUE *namep);
/**
* @copydoc rb_intern_str()
*
* @internal
*
* :FIXME: Can anyone tell us what is the difference between this one and
* rb_intern_str()? As far as @shyouhei reads the implementation it seems what
* rb_to_id() does is is just waste some CPU time, then call rb_intern_str().
* He hopes he is wrong.
*/
ID rb_to_id(VALUE str);
/**
* Identical to rb_id2name(), except it returns a frozen Ruby String instead of
* a C String.
*
* @param[in] id An id to query.
* @retval RUBY_Qfalse No such id ever existed in the history.
* @retval otherwise An instance of ::rb_cString with the name of id.
*
* @internal
*
* In reality "rb_id2str() is identical to rb_id2name() except it returns Ruby
* string" is just describing things upside down; truth is `rb_id2name(foo)` is
* a shorthand of `RSTRING_PTR(rb_id2str(foo))`.
*/
VALUE rb_id2str(ID id);
/**
* Obtain a frozen string representation of a symbol (not including the leading
* colon). Done without any object allocations.
*
* @param[in] symbol A ::rb_cSymbol instance to query.
* @return A frozen instance of ::rb_cString with the name of `symbol`.
* @note This does not create a permanent ::ID using the symbol.
*/
VALUE rb_sym2str(VALUE symbol);
/**
* Identical to rb_intern_str(), except it generates a dynamic symbol if
* necessary.
*
* @param[in] name The name of the id.
* @pre `name` must either be an instance of ::rb_cSymbol, or an
* instance of ::rb_cString, or responds to `#to_str` method.
* @exception rb_eTypeError Can't convert `name` into ::rb_cString.
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given name.
* @note These days Ruby internally has two kinds of symbols
* (static/dynamic). Symbols created using this function would
* become dynamic ones; i.e. would be garbage collected. It could
* be safer for you to use it than alternatives, when applicable.
*/
VALUE rb_to_symbol(VALUE name);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_check_id(), except it returns an instance of ::rb_cSymbol
* instead.
*
* @param[in,out] namep A pointer to a name to query.
* @pre The object referred by `*namep` must either be an instance
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
* @exception rb_eEncodingError Given string is non-ASCII.
* @retval RUBY_Qnil No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
* @see https://bugs.ruby-lang.org/issues/5072
*
* @internal
*
* @shyouhei doesn't know why this has to raise rb_eEncodingError.
*/
VALUE rb_check_symbol(volatile VALUE *namep);
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_NONNULL(())
/**
* This is a "tiny optimisation" over rb_intern(). If you pass a string
* _literal_, and if your C compiler can special-case strlen of such literal to
* strength-reduce into an integer constant expression, then this inline
* function can precalc a part of conversion.
*
* @note This function also works happily for non-constant strings. Why
* bother then? Just apply liberally to everything.
* @note But #rb_intern() could be faster on compilers with statement
* expressions, because they can cache the created ::ID.
* @param[in] str The name of the id.
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given str.
* @note These days Ruby internally has two kinds of symbols (static /
* dynamic). Symbols created using this function would become a
* static one; i.e. would never be garbage collected. It is up to
* you to avoid memory leaks. Think twice before using it.
*/
static inline ID
rb_intern_const(const char *str)
{
size_t len = strlen(str);
return rb_intern2(str, RBIMPL_CAST((long)len));
}
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL(())
/**
* @private
*
* This is an implementation detail of #rb_intern(). Just don't use it.
*/
static inline ID
rbimpl_intern_const(ID *ptr, const char *str)
{
while (! *ptr) {
*ptr = rb_intern_const(str);
}
return *ptr;
}
/**
* Old implementation detail of rb_intern().
* @deprecated Does anyone use it? Preserved for backward compat.
*/
#define RUBY_CONST_ID_CACHE(result, str) \
{ \
static ID rb_intern_id_cache; \
rbimpl_intern_const(&rb_intern_id_cache, (str)); \
result rb_intern_id_cache; \
}
/**
* Returns the cached ID for the given str in var, in compiler
* independent manner. Use this instead of GCC specific rb_intern()
* when you want to cache the ID on all platforms certainly.
*/
#define RUBY_CONST_ID(var, str) \
do { \
static ID rbimpl_id; \
(var) = rbimpl_intern_const(&rbimpl_id, (str)); \
} while (0)
#if defined(HAVE_STMT_AND_DECL_IN_EXPR)
/* GCC specific shorthand for RUBY_CONST_ID().
* __builtin_constant_p and statement expression is available
* since gcc-2.7.2.3 at least. */
#define rb_intern(str) \
(RBIMPL_CONSTANT_P(str) ? \
__extension__ ({ \
static ID rbimpl_id; \
rbimpl_intern_const(&rbimpl_id, (str)); \
}) : \
(rb_intern)(str))
#endif
#endif /* RBIMPL_SYMBOL_H */