File: intern.c

package info (click to toggle)
ruby-ox 2.14.23-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,504 kB
  • sloc: xml: 39,683; ansic: 9,626; ruby: 6,441; sh: 47; makefile: 2
file content (157 lines) | stat: -rw-r--r-- 4,581 bytes parent folder | download | duplicates (2)
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
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license details.

#include "intern.h"

#include <stdint.h>

#include "cache.h"
#include "ox.h"
#include "ruby/version.h"

// These are statics but in an attempt to stop the cross linking or maybe
// something in Ruby they all have been given an ox prefix.
static struct _cache *ox_str_cache = NULL;
static VALUE          ox_str_cache_obj;

static struct _cache *ox_sym_cache = NULL;
static VALUE          ox_sym_cache_obj;

static struct _cache *ox_attr_cache = NULL;
static VALUE          ox_attr_cache_obj;

static struct _cache *ox_id_cache = NULL;
static VALUE          ox_id_cache_obj;

static VALUE form_str(const char *str, size_t len) {
    return rb_str_freeze(rb_utf8_str_new(str, len));
}

static VALUE form_sym(const char *str, size_t len) {
    return rb_to_symbol(rb_str_freeze(rb_utf8_str_new(str, len)));
}

static VALUE form_attr(const char *str, size_t len) {
    char buf[256];

    if (sizeof(buf) - 2 <= len) {
        char *b = ALLOC_N(char, len + 2);
        ID    id;

        if ('~' == *str) {
            memcpy(b, str + 1, len - 1);
            b[len - 1] = '\0';
            len -= 2;
        } else {
            *b = '@';
            memcpy(b + 1, str, len);
            b[len + 1] = '\0';
        }
        id = rb_intern3(buf, len + 1, rb_utf8_encoding());
        xfree(b);
        return id;
    }
    if ('~' == *str) {
        memcpy(buf, str + 1, len - 1);
        buf[len - 1] = '\0';
        len -= 2;
    } else {
        *buf = '@';
        memcpy(buf + 1, str, len);
        buf[len + 1] = '\0';
    }
    return (VALUE)rb_intern3(buf, len + 1, rb_utf8_encoding());
}

static VALUE form_id(const char *str, size_t len) {
    return (VALUE)rb_intern3(str, len, rb_utf8_encoding());
}

void ox_hash_init(void) {
    VALUE cache_class = rb_define_class_under(Ox, "Cache", rb_cObject);
#if RUBY_API_VERSION_CODE >= 30200
    rb_undef_alloc_func(cache_class);
#endif

    ox_str_cache     = ox_cache_create(0, form_str, true, false);
    ox_str_cache_obj = TypedData_Wrap_Struct(cache_class, &ox_cache_type, ox_str_cache);
    rb_gc_register_address(&ox_str_cache_obj);

    ox_sym_cache     = ox_cache_create(0, form_sym, true, false);
    ox_sym_cache_obj = TypedData_Wrap_Struct(cache_class, &ox_cache_type, ox_sym_cache);
    rb_gc_register_address(&ox_sym_cache_obj);

    ox_attr_cache     = ox_cache_create(0, form_attr, false, false);
    ox_attr_cache_obj = TypedData_Wrap_Struct(cache_class, &ox_cache_type, ox_attr_cache);
    rb_gc_register_address(&ox_attr_cache_obj);

    ox_id_cache     = ox_cache_create(0, form_id, false, false);
    ox_id_cache_obj = TypedData_Wrap_Struct(cache_class, &ox_cache_type, ox_id_cache);
    rb_gc_register_address(&ox_id_cache_obj);
}

VALUE
ox_str_intern(const char *key, size_t len, const char **keyp) {
    // For huge cache sizes over half a million the rb_enc_interned_str
    // performs slightly better but at more "normal" size of a several
    // thousands the cache intern performs about 20% better.
#if HAVE_RB_ENC_INTERNED_STR && 0
    return rb_enc_interned_str(key, len, rb_utf8_encoding());
#else
    return ox_cache_intern(ox_str_cache, key, len, keyp);
#endif
}

VALUE
ox_sym_intern(const char *key, size_t len, const char **keyp) {
    return ox_cache_intern(ox_sym_cache, key, len, keyp);
}

ID ox_attr_intern(const char *key, size_t len) {
    return ox_cache_intern(ox_attr_cache, key, len, NULL);
}

ID ox_id_intern(const char *key, size_t len) {
    return ox_cache_intern(ox_id_cache, key, len, NULL);
}

char *ox_strndup(const char *s, size_t len) {
    char *d = ALLOC_N(char, len + 1);

    memcpy(d, s, len);
    d[len] = '\0';

    return d;
}

VALUE
ox_utf8_name(const char *str, size_t len, rb_encoding *encoding, const char **strp) {
    return ox_str_intern(str, len, strp);
}

VALUE
ox_utf8_sym(const char *str, size_t len, rb_encoding *encoding, const char **strp) {
    return ox_sym_intern(str, len, strp);
}

VALUE
ox_enc_sym(const char *str, size_t len, rb_encoding *encoding, const char **strp) {
    VALUE sym = rb_str_new2(str);

    rb_enc_associate(sym, encoding);
    if (NULL != strp) {
        *strp = StringValuePtr(sym);
    }
    return rb_to_symbol(sym);
}

VALUE
ox_enc_name(const char *str, size_t len, rb_encoding *encoding, const char **strp) {
    VALUE sym = rb_str_new2(str);

    rb_enc_associate(sym, encoding);
    if (NULL != strp) {
        *strp = StringValuePtr(sym);
    }
    return sym;
}