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
|
#ifndef RBIMPL_INTERN_HASH_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_HASH_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 Public APIs related to ::rb_cHash.
*/
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
#include "ruby/st.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* hash.c */
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_st_foreach(), except it raises exceptions when the callback
* function tampers the table during iterating over it.
*
* @param[in] st Table to iterate over.
* @param[in] func Callback function to apply.
* @param[in] arg Passed as-is to `func`.
* @exception rb_eRuntimeError `st` was tampered during iterating.
*
* @internal
*
* This is declared here because exceptions are Ruby level concept.
*
* This is in fact a very thin wrapper of rb_st_foreach_check().
*/
void rb_st_foreach_safe(struct st_table *st, st_foreach_callback_func *func, st_data_t arg);
/** @alias{rb_st_foreach_safe} */
#define st_foreach_safe rb_st_foreach_safe
/**
* Try converting an object to its hash representation using its `to_hash`
* method, if any. If there is no such thing, returns ::RUBY_Qnil.
*
* @param[in] obj Arbitrary ruby object to convert.
* @exception rb_eTypeError `obj.to_hash` returned something non-Hash.
* @retval RUBY_Qnil No conversion from `obj` to hash defined.
* @retval otherwise Converted hash representation of `obj`.
* @see rb_io_check_io
* @see rb_check_array_type
* @see rb_check_string_type
*
* @internal
*
* There is no rb_hash_to_hash() that analogous to rb_str_to_str().
* Intentional or ...?
*/
VALUE rb_check_hash_type(VALUE obj);
RBIMPL_ATTR_NONNULL(())
/**
* Iterates over a hash. This basically does the same thing as
* rb_st_foreach(). But because the passed hash is a Ruby object, its keys and
* values are both Ruby objects.
*
* @param[in] hash An instance of ::rb_cHash to iterate over.
* @param[in] func Callback function to yield.
* @param[in] arg Passed as-is to `func`.
* @exception rb_eRuntimeError `hash` was tampered during iterating.
*/
void rb_hash_foreach(VALUE hash, int (*func)(VALUE key, VALUE val, VALUE arg), VALUE arg);
/**
* Calculates a message authentication code of the passed object. The return
* value is a very small integer used as an index of a key of a table. In
* order to calculate the value this function calls `#hash` method of the
* passed object. Ruby provides you a default implementation. But if you
* implement your class in C, that default implementation cannot know the
* underlying data structure. You must implement your own `#hash` method then,
* which must return an integer of uniform distribution in a sufficiently
* instant manner.
*
* @param[in] obj Arbitrary Ruby object.
* @exception rb_eTypeError `obj.hash` returned something non-Integer.
* @return A small integer.
* @note `#hash` can return very big integers, but they get truncated.
*/
VALUE rb_hash(VALUE obj);
/**
* Creates a new, empty hash object.
*
* @return An allocated new instance of ::rb_cHash.
*/
VALUE rb_hash_new(void);
/**
* Identical to rb_hash_new(), except it additionally specifies how many keys
* it is expected to contain. This way you can create a hash that is large enough
* for your need. For large hashes it means it won't need to be reallocated and
* rehashed as much, improving performance.
*
* @param[in] capa Designed capacity of the hash.
* @return An empty Hash, whose capacity is `capa`.
*/
VALUE rb_hash_new_capa(long capa);
/**
* Duplicates a hash.
*
* @param[in] hash An instance of ::rb_cHash.
* @return An allocated new instance of ::rb_cHash, whose contents are
* a verbatim copy of from `hash`.
*/
VALUE rb_hash_dup(VALUE hash);
/** @alias{rb_obj_freeze} */
VALUE rb_hash_freeze(VALUE obj);
/**
* Queries the given key in the given hash table. If there is the key in the
* hash, returns the value associated with the key. Otherwise it returns the
* "default" value (defined per hash table).
*
* @param[in] hash Hash table to look into.
* @param[in] key Hash key to look for.
* @return Either the value associated with the key, or the default one if
* absent.
*/
VALUE rb_hash_aref(VALUE hash, VALUE key);
/**
* Identical to rb_hash_aref(), except it always returns ::RUBY_Qnil for
* misshits.
*
* @param[in] hash Hash table to look into.
* @param[in] key Hash key to look for.
* @return Either the value associated with the key, or ::RUBY_Qnil if
* absent.
* @note A hash can store ::RUBY_Qnil as an ordinary value. You cannot
* distinguish whether the key is missing, or just its associated
* value happens to be ::RUBY_Qnil, as far as you use this API.
*/
VALUE rb_hash_lookup(VALUE hash, VALUE key);
/**
* Identical to rb_hash_lookup(), except you can specify what to return on
* misshits. This is much like 2-arguments version of `Hash#fetch`.
*
* ```CXX
* VALUE hash;
* VALUE key;
* VALUE tmp = rb_obj_alloc(rb_cObject);
* VALUE val = rb_hash_lookup2(hash, key, tmp);
* if (val == tmp) {
* printf("misshit");
* }
* else {
* printf("hit");
* }
* ```
*
* @param[in] hash Hash table to look into.
* @param[in] key Hash key to look for.
* @param[in] def Default value.
* @retval def `hash` does not have `key`.
* @retval otherwise The value associated with `key`.
*/
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def);
/**
* Identical to rb_hash_lookup(), except it yields the (implicitly) passed
* block instead of returning ::RUBY_Qnil.
*
* @param[in] hash Hash table to look into.
* @param[in] key Hash key to look for.
* @exception rb_eKeyError No block given.
* @return Either the value associated with the key, or what the block
* evaluates to if absent.
*/
VALUE rb_hash_fetch(VALUE hash, VALUE key);
/**
* Inserts or replaces ("upsert"s) the objects into the given hash table. This
* basically associates the given value with the given key. On duplicate key
* this function updates its associated value with the given one. Otherwise it
* inserts the association at the end of the table.
*
* @param[out] hash Target hash table to modify.
* @param[in] key Arbitrary Ruby object.
* @param[in] val A value to be associated with `key`.
* @exception rb_eFrozenError `hash` is frozen.
* @return The passed `val`
* @post `val` is associated with `key` in `hash`.
*/
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val);
/**
* Swipes everything out of the passed hash table.
*
* @param[out] hash Target to clear.
* @exception rb_eFrozenError `hash`is frozen.
* @return The passed `hash`
* @post `hash` has no contents.
*/
VALUE rb_hash_clear(VALUE hash);
/**
* Deletes each entry for which the block returns a truthy value. If there is
* no block given, it returns an enumerator that does the thing.
*
* @param[out] hash Target hash to modify.
* @exception rb_eFrozenError `hash` is frozen.
* @retval hash The hash is modified.
* @retval otherwise An instance of ::rb_cEnumerator that does it.
*/
VALUE rb_hash_delete_if(VALUE hash);
/**
* Deletes the passed key from the passed hash table, if any.
*
* @param[out] hash Target hash to modify.
* @param[in] key Key to delete.
* @retval RUBY_Qnil `hash` has no such key as `key`.
* @retval otherwise What was associated with `key`.
* @post `hash` has no such key as `key`.
*/
VALUE rb_hash_delete(VALUE hash, VALUE key);
/**
* Inserts a list of key-value pairs into a hash table at once. It is
* semantically identical to repeatedly calling rb_hash_aset(), but can be
* faster than that.
*
* @param[in] argc Length of `argv`, must be even.
* @param[in] argv A list of key, value, key, value, ...
* @param[out] hash Target hash table to modify.
* @post `hash` has contents from `argv`.
* @note `argv` is allowed to be NULL as long as `argc` is zero.
*
* @internal
*
* What happens for duplicated keys? Well it silently discards older ones to
* accept the newest (rightmost) one. This behaviour also mimics repeated call
* of rb_hash_aset().
*/
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash);
/**
* Type of callback functions to pass to rb_hash_update_by().
*
* @param[in] newkey A key of the table.
* @param[in] oldkey Value associated with `key` in hash1.
* @param[in] value Value associated with `key` in hash2.
* @return Either one of the passed values to take.
*/
typedef VALUE rb_hash_update_func(VALUE newkey, VALUE oldkey, VALUE value);
/**
* Destructively merges two hash tables into one. It resolves key conflicts by
* calling the passed function and take its return value.
*
* @param[out] hash1 Target hash to be modified.
* @param[in] hash2 A hash to merge into `hash1`.
* @param[in] func Conflict reconciler.
* @exception rb_eFrozenError `hash1` is frozen.
* @exception rb_eRuntimeError `hash2` is updated instead.
* @return The passed `hash1`.
* @post Contents of `hash2` is merged into `hash1`.
* @note You can pass zero to `func`. This means values from `hash2`
* are always taken.
*/
VALUE rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func);
/* file.c */
/**
* This function is mysterious. What it does is not immediately obvious. Also
* what it does seems platform dependent.
*
* @param[in] path A local path.
* @retval 0 The "check" succeeded.
* @retval otherwise The "check" failed.
*/
int rb_path_check(const char *path);
/* hash.c */
/**
* Destructively removes every environment variables of the running process.
*
* @return The `ENV` object.
* @post The process has no environment variables.
*/
VALUE rb_env_clear(void);
/**
* Identical to #RHASH_SIZE(), except it returns the size in Ruby's integer
* instead of C's.
*
* @param[in] hash A hash object.
* @return The size of the hash.
*/
VALUE rb_hash_size(VALUE hash);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_HASH_H */
|