Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mruby
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
mruby
Commits
e8dcfe17
Commit
e8dcfe17
authored
Aug 06, 2018
by
Yukihiro "Matz" Matsumoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use segmented list to implement `Hash` [Experimental]
I know it's not hash at all, but reduce memory consumption.
parent
01c2f59e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
400 additions
and
239 deletions
+400
-239
include/mruby/hash.h
include/mruby/hash.h
+2
-3
src/hash.c
src/hash.c
+398
-236
No files found.
include/mruby/hash.h
View file @
e8dcfe17
...
@@ -18,7 +18,7 @@ MRB_BEGIN_DECL
...
@@ -18,7 +18,7 @@ MRB_BEGIN_DECL
struct
RHash
{
struct
RHash
{
MRB_OBJECT_HEADER
;
MRB_OBJECT_HEADER
;
struct
iv_tbl
*
iv
;
struct
iv_tbl
*
iv
;
struct
kh_h
t
*
ht
;
struct
seglis
t
*
ht
;
};
};
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
...
@@ -76,7 +76,7 @@ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key);
...
@@ -76,7 +76,7 @@ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key);
*
*
* Equivalent to:
* Equivalent to:
*
*
* hash.
hash_
key?(key) ? hash[key] : def
* hash.key?(key) ? hash[key] : def
*
*
* @param mrb The mruby state reference.
* @param mrb The mruby state reference.
* @param hash The target hash.
* @param hash The target hash.
...
@@ -199,7 +199,6 @@ KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
...
@@ -199,7 +199,6 @@ KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
#define RHASH_TBL(h) (RHASH(h)->ht)
#define RHASH_TBL(h) (RHASH(h)->ht)
#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone"))
#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone"))
#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h)
#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h)
MRB_API
struct
kh_ht
*
mrb_hash_tbl
(
mrb_state
*
mrb
,
mrb_value
hash
);
#define MRB_HASH_DEFAULT 1
#define MRB_HASH_DEFAULT 1
#define MRB_HASH_PROC_DEFAULT 2
#define MRB_HASH_PROC_DEFAULT 2
...
...
src/hash.c
View file @
e8dcfe17
...
@@ -8,7 +8,6 @@
...
@@ -8,7 +8,6 @@
#include <mruby/array.h>
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/class.h>
#include <mruby/hash.h>
#include <mruby/hash.h>
#include <mruby/khash.h>
#include <mruby/string.h>
#include <mruby/string.h>
#include <mruby/variable.h>
#include <mruby/variable.h>
...
@@ -47,7 +46,7 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
...
@@ -47,7 +46,7 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
return
kh_int_hash_func
(
mrb
,
h
);
return
kh_int_hash_func
(
mrb
,
h
);
}
}
static
inline
khint_t
static
inline
mrb_bool
mrb_hash_ht_hash_equal
(
mrb_state
*
mrb
,
mrb_value
a
,
mrb_value
b
)
mrb_hash_ht_hash_equal
(
mrb_state
*
mrb
,
mrb_value
a
,
mrb_value
b
)
{
{
enum
mrb_vtype
t
=
mrb_type
(
a
);
enum
mrb_vtype
t
=
mrb_type
(
a
);
...
@@ -89,7 +88,251 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
...
@@ -89,7 +88,251 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
}
}
}
}
KHASH_DEFINE
(
ht
,
mrb_value
,
mrb_hash_value
,
TRUE
,
mrb_hash_ht_hash_func
,
mrb_hash_ht_hash_equal
)
/* return non zero to break the loop */
typedef
int
(
sg_foreach_func
)(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
data
);
#ifndef MRB_SG_SEGMENT_SIZE
#define MRB_SG_SEGMENT_SIZE 5
#endif
typedef
struct
segment
{
mrb_value
key
[
MRB_SG_SEGMENT_SIZE
];
mrb_value
val
[
MRB_SG_SEGMENT_SIZE
];
struct
segment
*
next
;
}
segment
;
/* Instance variable table structure */
typedef
struct
seglist
{
segment
*
rootseg
;
size_t
size
;
size_t
last_len
;
}
seglist
;
/* Creates the instance variable table. */
static
seglist
*
sg_new
(
mrb_state
*
mrb
)
{
seglist
*
t
;
t
=
(
seglist
*
)
mrb_malloc
(
mrb
,
sizeof
(
seglist
));
t
->
size
=
0
;
t
->
rootseg
=
NULL
;
t
->
last_len
=
0
;
return
t
;
}
/* Set the value for the symbol in the instance variable table. */
static
void
sg_put
(
mrb_state
*
mrb
,
seglist
*
t
,
mrb_value
key
,
mrb_value
val
)
{
segment
*
seg
;
segment
*
prev
=
NULL
;
size_t
i
;
if
(
t
==
NULL
)
return
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
for
(
i
=
0
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
mrb_value
k
=
seg
->
key
[
i
];
/* Found room in last segment after last_len */
if
(
!
seg
->
next
&&
i
>=
t
->
last_len
)
{
seg
->
key
[
i
]
=
key
;
seg
->
val
[
i
]
=
val
;
t
->
last_len
=
i
+
1
;
t
->
size
++
;
return
;
}
if
(
mrb_hash_ht_hash_equal
(
mrb
,
k
,
key
))
{
seg
->
val
[
i
]
=
val
;
return
;
}
}
prev
=
seg
;
seg
=
seg
->
next
;
}
/* Not found */
t
->
size
++
;
seg
=
(
segment
*
)
mrb_malloc
(
mrb
,
sizeof
(
segment
));
if
(
!
seg
)
return
;
seg
->
next
=
NULL
;
seg
->
key
[
0
]
=
key
;
seg
->
val
[
0
]
=
val
;
t
->
last_len
=
1
;
if
(
prev
)
{
prev
->
next
=
seg
;
}
else
{
t
->
rootseg
=
seg
;
}
}
/* Get a value for a symbol from the instance variable table. */
static
mrb_bool
sg_get
(
mrb_state
*
mrb
,
seglist
*
t
,
mrb_value
key
,
mrb_value
*
vp
)
{
segment
*
seg
;
size_t
i
;
if
(
t
==
NULL
)
return
FALSE
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
for
(
i
=
0
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
mrb_value
k
=
seg
->
key
[
i
];
if
(
!
seg
->
next
&&
i
>=
t
->
last_len
)
{
return
FALSE
;
}
if
(
mrb_hash_ht_hash_equal
(
mrb
,
k
,
key
))
{
if
(
vp
)
*
vp
=
seg
->
val
[
i
];
return
TRUE
;
}
}
seg
=
seg
->
next
;
}
return
FALSE
;
}
/* Deletes the value for the symbol from the instance variable table. */
static
mrb_bool
sg_del
(
mrb_state
*
mrb
,
seglist
*
t
,
mrb_value
key
,
mrb_value
*
vp
)
{
segment
*
seg
;
size_t
i
;
if
(
t
==
NULL
)
return
FALSE
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
for
(
i
=
0
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
mrb_value
k
=
seg
->
key
[
i
];
if
(
!
seg
->
next
&&
i
>=
t
->
last_len
)
{
/* not found */
return
FALSE
;
}
if
(
mrb_hash_ht_hash_equal
(
mrb
,
k
,
key
))
{
segment
*
sg0
;
size_t
i0
;
t
->
size
--
;
if
(
vp
)
*
vp
=
seg
->
val
[
i
];
sg0
=
seg
;
i0
=
i
;
while
(
seg
)
{
for
(
i
++
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
if
(
!
seg
->
next
&&
i
>=
t
->
last_len
)
{
t
->
last_len
--
;
if
(
t
->
last_len
==
0
&&
sg0
!=
seg
)
{
sg0
->
next
=
NULL
;
t
->
last_len
=
MRB_SG_SEGMENT_SIZE
;
mrb_free
(
mrb
,
seg
);
}
return
TRUE
;
}
sg0
->
key
[
i0
]
=
seg
->
key
[
i
];
sg0
->
val
[
i0
]
=
seg
->
val
[
i
];
i0
=
i
;
}
sg0
=
seg
;
seg
=
seg
->
next
;
}
t
->
last_len
--
;
return
TRUE
;
}
}
seg
=
seg
->
next
;
}
return
FALSE
;
}
/* Iterates over the instance variable table. */
static
void
sg_foreach
(
mrb_state
*
mrb
,
seglist
*
t
,
sg_foreach_func
*
func
,
void
*
p
)
{
segment
*
seg
;
size_t
i
;
if
(
t
==
NULL
)
return
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
for
(
i
=
0
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
/* no value in last segment after last_len */
if
(
!
seg
->
next
&&
i
>=
t
->
last_len
)
{
return
;
}
if
((
*
func
)(
mrb
,
seg
->
key
[
i
],
seg
->
val
[
i
],
p
)
!=
0
)
return
;
}
seg
=
seg
->
next
;
}
}
/* Get the size of the instance variable table. */
static
size_t
sg_size
(
mrb_state
*
mrb
,
seglist
*
t
)
{
segment
*
seg
;
size_t
size
=
0
;
if
(
t
==
NULL
)
return
0
;
if
(
t
->
size
>
0
)
return
t
->
size
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
if
(
seg
->
next
==
NULL
)
{
size
+=
t
->
last_len
;
return
size
;
}
seg
=
seg
->
next
;
size
+=
MRB_SG_SEGMENT_SIZE
;
}
/* empty seglist */
return
0
;
}
/* Copy the instance variable table. */
static
seglist
*
sg_copy
(
mrb_state
*
mrb
,
seglist
*
t
)
{
segment
*
seg
;
seglist
*
t2
;
size_t
i
;
seg
=
t
->
rootseg
;
t2
=
sg_new
(
mrb
);
while
(
seg
!=
NULL
)
{
for
(
i
=
0
;
i
<
MRB_SG_SEGMENT_SIZE
;
i
++
)
{
mrb_value
key
=
seg
->
key
[
i
];
mrb_value
val
=
seg
->
val
[
i
];
if
((
seg
->
next
==
NULL
)
&&
(
i
>=
t
->
last_len
))
{
return
t2
;
}
sg_put
(
mrb
,
t2
,
key
,
val
);
}
seg
=
seg
->
next
;
}
return
t2
;
}
/* Free memory of the instance variable table. */
static
void
sg_free
(
mrb_state
*
mrb
,
seglist
*
t
)
{
segment
*
seg
;
if
(
!
t
)
return
;
seg
=
t
->
rootseg
;
while
(
seg
)
{
segment
*
p
=
seg
;
seg
=
seg
->
next
;
mrb_free
(
mrb
,
p
);
}
mrb_free
(
mrb
,
t
);
}
static
void
mrb_hash_modify
(
mrb_state
*
mrb
,
mrb_value
hash
);
static
void
mrb_hash_modify
(
mrb_state
*
mrb
,
mrb_value
hash
);
...
@@ -105,57 +348,55 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
...
@@ -105,57 +348,55 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
#define KEY(key) mrb_hash_ht_key(mrb, key)
#define KEY(key) mrb_hash_ht_key(mrb, key)
static
int
hash_mark_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
p
)
{
mrb_gc_mark_value
(
mrb
,
key
);
mrb_gc_mark_value
(
mrb
,
val
);
return
0
;
}
void
void
mrb_gc_mark_hash
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
mrb_gc_mark_hash
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
{
{
khiter_t
k
;
sg_foreach
(
mrb
,
hash
->
ht
,
hash_mark_i
,
NULL
);
khash_t
(
ht
)
*
h
=
hash
->
ht
;
if
(
!
h
)
return
;
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
if
(
kh_exist
(
h
,
k
))
{
mrb_value
key
=
kh_key
(
h
,
k
);
mrb_value
val
=
kh_value
(
h
,
k
).
v
;
mrb_gc_mark_value
(
mrb
,
key
);
mrb_gc_mark_value
(
mrb
,
val
);
}
}
}
}
size_t
size_t
mrb_gc_mark_hash_size
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
mrb_gc_mark_hash_size
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
{
{
if
(
!
hash
->
ht
)
return
0
;
if
(
!
hash
->
ht
)
return
0
;
return
kh_size
(
hash
->
ht
)
*
2
;
return
sg_size
(
mrb
,
hash
->
ht
)
*
2
;
}
}
void
void
mrb_gc_free_hash
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
mrb_gc_free_hash
(
mrb_state
*
mrb
,
struct
RHash
*
hash
)
{
{
if
(
hash
->
ht
)
kh_destroy
(
ht
,
mrb
,
hash
->
ht
);
sg_free
(
mrb
,
hash
->
ht
);
}
}
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_new
_capa
(
mrb_state
*
mrb
,
mrb_int
capa
)
mrb_hash_new
(
mrb_state
*
mrb
)
{
{
struct
RHash
*
h
;
struct
RHash
*
h
;
h
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
h
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
/* khash needs 1/4 empty space so it is not resized immediately */
h
->
ht
=
0
;
if
(
capa
==
0
)
h
->
ht
=
0
;
else
h
->
ht
=
kh_init_size
(
ht
,
mrb
,
(
khint_t
)(
capa
*
4
/
3
));
h
->
iv
=
0
;
h
->
iv
=
0
;
return
mrb_obj_value
(
h
);
return
mrb_obj_value
(
h
);
}
}
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_new
(
mrb_state
*
mrb
)
mrb_hash_new
_capa
(
mrb_state
*
mrb
,
mrb_int
capa
)
{
{
return
mrb_hash_new_capa
(
mrb
,
0
);
struct
RHash
*
h
;
h
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
/* preallocate segment list */
h
->
ht
=
sg_new
(
mrb
);
/* capacity ignored */
h
->
iv
=
0
;
return
mrb_obj_value
(
h
);
}
}
static
mrb_value
mrb_hash_default
(
mrb_state
*
mrb
,
mrb_value
hash
);
static
mrb_value
mrb_hash_default
(
mrb_state
*
mrb
,
mrb_value
hash
);
...
@@ -166,7 +407,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
...
@@ -166,7 +407,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
{
{
mrb_value
orig
;
mrb_value
orig
;
struct
RHash
*
copy
;
struct
RHash
*
copy
;
khash_t
(
ht
)
*
orig_h
;
seglist
*
orig_h
;
mrb_value
ifnone
,
vret
;
mrb_value
ifnone
,
vret
;
mrb_get_args
(
mrb
,
"o"
,
&
orig
);
mrb_get_args
(
mrb
,
"o"
,
&
orig
);
...
@@ -177,22 +418,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
...
@@ -177,22 +418,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
orig_h
=
RHASH_TBL
(
self
);
orig_h
=
RHASH_TBL
(
self
);
copy
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
copy
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
copy
->
ht
=
kh_init
(
ht
,
mrb
);
copy
->
ht
=
sg_copy
(
mrb
,
orig_h
);
if
(
orig_h
&&
kh_size
(
orig_h
)
>
0
)
{
khash_t
(
ht
)
*
copy_h
=
copy
->
ht
;
khiter_t
k
,
copy_k
;
for
(
k
=
kh_begin
(
orig_h
);
k
!=
kh_end
(
orig_h
);
k
++
)
{
if
(
kh_exist
(
orig_h
,
k
))
{
int
ai
=
mrb_gc_arena_save
(
mrb
);
copy_k
=
kh_put
(
ht
,
mrb
,
copy_h
,
KEY
(
kh_key
(
orig_h
,
k
)));
mrb_gc_arena_restore
(
mrb
,
ai
);
kh_val
(
copy_h
,
copy_k
).
v
=
kh_val
(
orig_h
,
k
).
v
;
kh_val
(
copy_h
,
copy_k
).
n
=
kh_size
(
copy_h
)
-
1
;
}
}
}
if
(
MRB_RHASH_DEFAULT_P
(
self
))
{
if
(
MRB_RHASH_DEFAULT_P
(
self
))
{
copy
->
flags
|=
MRB_HASH_DEFAULT
;
copy
->
flags
|=
MRB_HASH_DEFAULT
;
...
@@ -208,65 +434,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
...
@@ -208,65 +434,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
return
vret
;
return
vret
;
}
}
static
int
check_kdict_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
data
)
{
if
(
!
mrb_symbol_p
(
key
))
{
mrb_raise
(
mrb
,
E_ARGUMENT_ERROR
,
"keyword argument hash with non symbol keys"
);
}
return
0
;
}
void
void
mrb_hash_check_kdict
(
mrb_state
*
mrb
,
mrb_value
self
)
mrb_hash_check_kdict
(
mrb_state
*
mrb
,
mrb_value
self
)
{
{
khash_t
(
ht
)
*
orig_h
;
seglist
*
sg
;
khiter_t
k
;
int
nosym
=
FALSE
;
orig_h
=
RHASH_TBL
(
self
);
sg
=
RHASH_TBL
(
self
);
if
(
!
orig_h
||
kh_size
(
orig_h
)
==
0
)
return
;
if
(
!
sg
||
sg_size
(
mrb
,
sg
)
==
0
)
return
;
for
(
k
=
kh_begin
(
orig_h
);
k
!=
kh_end
(
orig_h
);
k
++
)
{
sg_foreach
(
mrb
,
sg
,
check_kdict_i
,
NULL
);
if
(
kh_exist
(
orig_h
,
k
))
{
mrb_value
key
=
kh_key
(
orig_h
,
k
);
if
(
!
mrb_symbol_p
(
key
))
nosym
=
TRUE
;
}
}
if
(
nosym
)
{
mrb_raise
(
mrb
,
E_ARGUMENT_ERROR
,
"keyword argument hash with non symbol keys"
);
}
}
}
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_dup
(
mrb_state
*
mrb
,
mrb_value
self
)
mrb_hash_dup
(
mrb_state
*
mrb
,
mrb_value
self
)
{
{
struct
RHash
*
copy
;
struct
RHash
*
copy
;
khash_t
(
ht
)
*
orig_h
;
seglist
*
orig_h
;
orig_h
=
RHASH_TBL
(
self
);
orig_h
=
RHASH_TBL
(
self
);
copy
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
copy
=
(
struct
RHash
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_HASH
,
mrb
->
hash_class
);
copy
->
ht
=
kh_init
(
ht
,
mrb
);
copy
->
ht
=
orig_h
?
sg_copy
(
mrb
,
orig_h
)
:
NULL
;
if
(
orig_h
&&
kh_size
(
orig_h
)
>
0
)
{
int
ai
=
mrb_gc_arena_save
(
mrb
);
khash_t
(
ht
)
*
copy_h
=
copy
->
ht
;
khiter_t
k
,
copy_k
;
for
(
k
=
kh_begin
(
orig_h
);
k
!=
kh_end
(
orig_h
);
k
++
)
{
if
(
kh_exist
(
orig_h
,
k
))
{
copy_k
=
kh_put
(
ht
,
mrb
,
copy_h
,
KEY
(
kh_key
(
orig_h
,
k
)));
mrb_gc_arena_restore
(
mrb
,
ai
);
kh_val
(
copy_h
,
copy_k
).
v
=
kh_val
(
orig_h
,
k
).
v
;
kh_val
(
copy_h
,
copy_k
).
n
=
kh_size
(
copy_h
)
-
1
;
}
}
}
return
mrb_obj_value
(
copy
);
return
mrb_obj_value
(
copy
);
}
}
MRB_API
mrb_bool
mrb_hash_has_key_p
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
{
if
(
sg_get
(
mrb
,
RHASH_TBL
(
hash
),
key
,
NULL
))
{
return
TRUE
;
}
return
FALSE
;
}
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_get
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
mrb_hash_get
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
mrb_value
val
;
khiter_t
k
;
mrb_sym
mid
;
mrb_sym
mid
;
if
(
h
)
{
if
(
sg_get
(
mrb
,
RHASH_TBL
(
hash
),
key
,
&
val
))
{
k
=
kh_get
(
ht
,
mrb
,
h
,
key
);
return
val
;
if
(
k
!=
kh_end
(
h
))
return
kh_value
(
h
,
k
).
v
;
}
}
mid
=
mrb_intern_lit
(
mrb
,
"default"
);
mid
=
mrb_intern_lit
(
mrb
,
"default"
);
...
@@ -280,15 +495,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
...
@@ -280,15 +495,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_fetch
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
,
mrb_value
def
)
mrb_hash_fetch
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
,
mrb_value
def
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
mrb_value
val
;
khiter_t
k
;
if
(
h
)
{
if
(
sg_get
(
mrb
,
RHASH_TBL
(
hash
),
key
,
&
val
))
{
k
=
kh_get
(
ht
,
mrb
,
h
,
key
);
return
val
;
if
(
k
!=
kh_end
(
h
))
return
kh_value
(
h
,
k
).
v
;
}
}
/* not found */
/* not found */
return
def
;
return
def
;
}
}
...
@@ -296,25 +507,9 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
...
@@ -296,25 +507,9 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
MRB_API
void
MRB_API
void
mrb_hash_set
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
,
mrb_value
val
)
mrb_hash_set
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
,
mrb_value
val
)
{
{
khash_t
(
ht
)
*
h
;
khiter_t
k
;
int
r
;
mrb_hash_modify
(
mrb
,
hash
);
mrb_hash_modify
(
mrb
,
hash
);
h
=
RHASH_TBL
(
hash
);
if
(
!
h
)
h
=
RHASH_TBL
(
hash
)
=
kh_init
(
ht
,
mrb
);
k
=
kh_put2
(
ht
,
mrb
,
h
,
key
,
&
r
);
kh_value
(
h
,
k
).
v
=
val
;
if
(
r
!=
0
)
{
/* expand */
int
ai
=
mrb_gc_arena_save
(
mrb
);
key
=
kh_key
(
h
,
k
)
=
KEY
(
key
);
mrb_gc_arena_restore
(
mrb
,
ai
);
kh_value
(
h
,
k
).
n
=
kh_size
(
h
)
-
1
;
}
sg_put
(
mrb
,
RHASH_TBL
(
hash
),
key
,
val
);
mrb_field_write_barrier_value
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash
),
key
);
mrb_field_write_barrier_value
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash
),
key
);
mrb_field_write_barrier_value
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash
),
val
);
mrb_field_write_barrier_value
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash
),
val
);
return
;
return
;
...
@@ -332,24 +527,16 @@ mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
...
@@ -332,24 +527,16 @@ mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
return
mrb_check_convert_type
(
mrb
,
hash
,
MRB_TT_HASH
,
"Hash"
,
"to_hash"
);
return
mrb_check_convert_type
(
mrb
,
hash
,
MRB_TT_HASH
,
"Hash"
,
"to_hash"
);
}
}
MRB_API
khash_t
(
ht
)
*
mrb_hash_tbl
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
if
(
!
h
)
{
return
RHASH_TBL
(
hash
)
=
kh_init
(
ht
,
mrb
);
}
return
h
;
}
static
void
static
void
mrb_hash_modify
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_modify
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
if
(
MRB_FROZEN_P
(
mrb_hash_ptr
(
hash
)))
{
if
(
MRB_FROZEN_P
(
mrb_hash_ptr
(
hash
)))
{
mrb_raise
(
mrb
,
E_FROZEN_ERROR
,
"can't modify frozen hash"
);
mrb_raise
(
mrb
,
E_FROZEN_ERROR
,
"can't modify frozen hash"
);
}
}
mrb_hash_tbl
(
mrb
,
hash
);
if
(
!
RHASH_TBL
(
hash
))
{
RHASH_TBL
(
hash
)
=
sg_new
(
mrb
);
}
}
}
/* 15.2.13.4.16 */
/* 15.2.13.4.16 */
...
@@ -589,23 +776,11 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
...
@@ -589,23 +776,11 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_delete_key
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
mrb_hash_delete_key
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
seglist
*
sg
=
RHASH_TBL
(
hash
);
khiter_t
k
;
mrb_value
del_val
;
mrb_value
delVal
;
mrb_int
n
;
if
(
sg_del
(
mrb
,
sg
,
key
,
&
del_val
))
{
return
del_val
;
if
(
h
)
{
k
=
kh_get
(
ht
,
mrb
,
h
,
key
);
if
(
k
!=
kh_end
(
h
))
{
delVal
=
kh_value
(
h
,
k
).
v
;
n
=
kh_value
(
h
,
k
).
n
;
kh_del
(
ht
,
mrb
,
h
,
k
);
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
if
(
!
kh_exist
(
h
,
k
))
continue
;
if
(
kh_value
(
h
,
k
).
n
>
n
)
kh_value
(
h
,
k
).
n
--
;
}
return
delVal
;
}
}
}
/* not found */
/* not found */
...
@@ -657,22 +832,14 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
...
@@ -657,22 +832,14 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
static
mrb_value
static
mrb_value
mrb_hash_shift
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_shift
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
seglist
*
sg
=
RHASH_TBL
(
hash
);
khiter_t
k
;
mrb_value
delKey
,
delVal
;
mrb_hash_modify
(
mrb
,
hash
);
mrb_hash_modify
(
mrb
,
hash
);
if
(
h
&&
kh_size
(
h
)
>
0
)
{
if
(
sg
&&
sg_size
(
mrb
,
sg
)
>
0
)
{
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
mrb_value
del_key
=
sg
->
rootseg
->
key
[
0
];
if
(
!
kh_exist
(
h
,
k
))
continue
;
mrb_value
del_val
=
sg
->
rootseg
->
val
[
0
];
sg_del
(
mrb
,
sg
,
del_key
,
NULL
);
delKey
=
kh_key
(
h
,
k
);
return
mrb_assoc_new
(
mrb
,
del_key
,
del_val
);
mrb_gc_protect
(
mrb
,
delKey
);
delVal
=
mrb_hash_delete_key
(
mrb
,
hash
,
delKey
);
mrb_gc_protect
(
mrb
,
delVal
);
return
mrb_assoc_new
(
mrb
,
delKey
,
delVal
);
}
}
}
if
(
MRB_RHASH_DEFAULT_P
(
hash
))
{
if
(
MRB_RHASH_DEFAULT_P
(
hash
))
{
...
@@ -701,10 +868,13 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
...
@@ -701,10 +868,13 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_clear
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_clear
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
seglist
*
sg
=
RHASH_TBL
(
hash
);
mrb_hash_modify
(
mrb
,
hash
);
mrb_hash_modify
(
mrb
,
hash
);
if
(
h
)
kh_clear
(
ht
,
mrb
,
h
);
if
(
sg
)
{
sg_free
(
mrb
,
sg
);
RHASH_TBL
(
hash
)
=
NULL
;
}
return
hash
;
return
hash
;
}
}
...
@@ -754,10 +924,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
...
@@ -754,10 +924,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
static
mrb_value
static
mrb_value
mrb_hash_size_m
(
mrb_state
*
mrb
,
mrb_value
self
)
mrb_hash_size_m
(
mrb_state
*
mrb
,
mrb_value
self
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
self
);
seglist
*
sg
=
RHASH_TBL
(
self
);
if
(
!
h
)
return
mrb_fixnum_value
(
0
);
if
(
!
sg
)
return
mrb_fixnum_value
(
0
);
return
mrb_fixnum_value
(
kh_size
(
h
));
return
mrb_fixnum_value
(
sg_size
(
mrb
,
sg
));
}
MRB_API
mrb_bool
mrb_hash_empty_p
(
mrb_state
*
mrb
,
mrb_value
self
)
{
seglist
*
sg
=
RHASH_TBL
(
self
);
if
(
!
sg
)
return
TRUE
;
return
sg_size
(
mrb
,
sg
)
==
0
;
}
}
/* 15.2.13.4.12 */
/* 15.2.13.4.12 */
...
@@ -770,21 +949,10 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
...
@@ -770,21 +949,10 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
* {}.empty? #=> true
* {}.empty? #=> true
*
*
*/
*/
MRB_API
mrb_bool
mrb_hash_empty_p
(
mrb_state
*
mrb
,
mrb_value
self
)
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
self
);
if
(
h
)
return
kh_size
(
h
)
==
0
;
return
TRUE
;
}
static
mrb_value
static
mrb_value
mrb_hash_empty_m
(
mrb_state
*
mrb
,
mrb_value
self
)
mrb_hash_empty_m
(
mrb_state
*
mrb
,
mrb_value
self
)
{
{
if
(
mrb_hash_empty_p
(
mrb
,
self
))
return
mrb_bool_value
(
mrb_hash_empty_p
(
mrb
,
self
));
return
mrb_true_value
();
return
mrb_false_value
();
}
}
/* 15.2.13.4.29 (x)*/
/* 15.2.13.4.29 (x)*/
...
@@ -801,6 +969,13 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash)
...
@@ -801,6 +969,13 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash)
return
hash
;
return
hash
;
}
}
static
int
hash_keys_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
p
)
{
mrb_ary_push
(
mrb
,
*
(
mrb_value
*
)
p
,
key
);
return
0
;
}
/* 15.2.13.4.19 */
/* 15.2.13.4.19 */
/*
/*
* call-seq:
* call-seq:
...
@@ -817,33 +992,24 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash)
...
@@ -817,33 +992,24 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash)
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_keys
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_keys
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
seglist
*
sg
=
RHASH_TBL
(
hash
);
khiter_t
k
;
size_t
size
;
mrb_int
end
;
mrb_value
ary
;
mrb_value
ary
;
mrb_value
*
p
;
if
(
!
sg
||
(
size
=
sg_size
(
mrb
,
sg
))
==
0
)
if
(
!
h
||
kh_size
(
h
)
==
0
)
return
mrb_ary_new
(
mrb
);
return
mrb_ary_new
(
mrb
);
ary
=
mrb_ary_new_capa
(
mrb
,
kh_size
(
h
));
ary
=
mrb_ary_new_capa
(
mrb
,
size
);
end
=
kh_size
(
h
)
-
1
;
sg_foreach
(
mrb
,
sg
,
hash_keys_i
,
(
void
*
)
&
ary
);
mrb_ary_set
(
mrb
,
ary
,
end
,
mrb_nil_value
());
p
=
RARRAY_PTR
(
ary
);
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
if
(
kh_exist
(
h
,
k
))
{
mrb_value
kv
=
kh_key
(
h
,
k
);
mrb_hash_value
hv
=
kh_value
(
h
,
k
);
if
(
hv
.
n
<=
end
)
{
p
[
hv
.
n
]
=
kv
;
}
else
{
p
[
end
]
=
kv
;
}
}
}
return
ary
;
return
ary
;
}
}
static
int
hash_vals_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
p
)
{
mrb_ary_push
(
mrb
,
*
(
mrb_value
*
)
p
,
val
);
return
0
;
}
/* 15.2.13.4.28 */
/* 15.2.13.4.28 */
/*
/*
* call-seq:
* call-seq:
...
@@ -860,19 +1026,14 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash)
...
@@ -860,19 +1026,14 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash)
MRB_API
mrb_value
MRB_API
mrb_value
mrb_hash_values
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_values
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
khash_t
(
ht
)
*
h
=
RHASH_TBL
(
hash
);
seglist
*
sg
=
RHASH_TBL
(
hash
);
khiter_t
k
;
size_t
size
;
mrb_value
ary
;
mrb_value
ary
;
if
(
!
h
)
return
mrb_ary_new
(
mrb
);
if
(
!
sg
||
(
size
=
sg_size
(
mrb
,
sg
))
==
0
)
ary
=
mrb_ary_new_capa
(
mrb
,
kh_size
(
h
));
return
mrb_ary_new
(
mrb
);
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
ary
=
mrb_ary_new_capa
(
mrb
,
size
);
if
(
kh_exist
(
h
,
k
))
{
sg_foreach
(
mrb
,
sg
,
hash_vals_i
,
(
void
*
)
&
ary
);
mrb_hash_value
hv
=
kh_value
(
h
,
k
);
mrb_ary_set
(
mrb
,
ary
,
hv
.
n
,
hv
.
v
);
}
}
return
ary
;
return
ary
;
}
}
...
@@ -898,13 +1059,11 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
...
@@ -898,13 +1059,11 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
MRB_API
mrb_bool
MRB_API
mrb_bool
mrb_hash_key_p
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
mrb_hash_key_p
(
mrb_state
*
mrb
,
mrb_value
hash
,
mrb_value
key
)
{
{
khash_t
(
ht
)
*
h
;
seglist
*
sg
;
khiter_t
k
;
h
=
RHASH_TBL
(
hash
);
sg
=
RHASH_TBL
(
hash
);
if
(
h
)
{
if
(
sg_get
(
mrb
,
sg
,
key
,
NULL
))
{
k
=
kh_get
(
ht
,
mrb
,
h
,
key
);
return
TRUE
;
return
k
!=
kh_end
(
h
);
}
}
return
FALSE
;
return
FALSE
;
}
}
...
@@ -920,6 +1079,23 @@ mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
...
@@ -920,6 +1079,23 @@ mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
return
mrb_bool_value
(
key_p
);
return
mrb_bool_value
(
key_p
);
}
}
struct
has_v_arg
{
mrb_bool
found
;
mrb_value
val
;
};
static
int
hash_has_value_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
p
)
{
struct
has_v_arg
*
arg
=
(
struct
has_v_arg
*
)
p
;
if
(
mrb_equal
(
mrb
,
arg
->
val
,
val
))
{
arg
->
found
=
TRUE
;
return
1
;
}
return
0
;
}
/* 15.2.13.4.14 */
/* 15.2.13.4.14 */
/* 15.2.13.4.27 */
/* 15.2.13.4.27 */
/*
/*
...
@@ -939,30 +1115,28 @@ static mrb_value
...
@@ -939,30 +1115,28 @@ static mrb_value
mrb_hash_has_value
(
mrb_state
*
mrb
,
mrb_value
hash
)
mrb_hash_has_value
(
mrb_state
*
mrb
,
mrb_value
hash
)
{
{
mrb_value
val
;
mrb_value
val
;
khash_t
(
ht
)
*
h
;
struct
has_v_arg
arg
;
khiter_t
k
;
mrb_get_args
(
mrb
,
"o"
,
&
val
);
mrb_get_args
(
mrb
,
"o"
,
&
val
);
h
=
RHASH_TBL
(
hash
);
arg
.
found
=
FALSE
;
arg
.
val
=
val
;
sg_foreach
(
mrb
,
RHASH_TBL
(
hash
),
hash_has_value_i
,
&
arg
);
return
mrb_bool_value
(
arg
.
found
);
}
if
(
h
)
{
static
int
for
(
k
=
kh_begin
(
h
);
k
!=
kh_end
(
h
);
k
++
)
{
merge_i
(
mrb_state
*
mrb
,
mrb_value
key
,
mrb_value
val
,
void
*
data
)
if
(
!
kh_exist
(
h
,
k
))
continue
;
{
seglist
*
h1
=
(
seglist
*
)
data
;
if
(
mrb_equal
(
mrb
,
kh_value
(
h
,
k
).
v
,
val
))
{
sg_put
(
mrb
,
h1
,
key
,
val
);
return
mrb_true_value
();
return
0
;
}
}
}
return
mrb_false_value
();
}
}
MRB_API
void
MRB_API
void
mrb_hash_merge
(
mrb_state
*
mrb
,
mrb_value
hash1
,
mrb_value
hash2
)
mrb_hash_merge
(
mrb_state
*
mrb
,
mrb_value
hash1
,
mrb_value
hash2
)
{
{
khash_t
(
ht
)
*
h1
;
seglist
*
h1
,
*
h2
;
khash_t
(
ht
)
*
h2
;
khiter_t
k
;
mrb_hash_modify
(
mrb
,
hash1
);
mrb_hash_modify
(
mrb
,
hash1
);
hash2
=
mrb_ensure_hash_type
(
mrb
,
hash2
);
hash2
=
mrb_ensure_hash_type
(
mrb
,
hash2
);
...
@@ -971,22 +1145,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
...
@@ -971,22 +1145,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
if
(
!
h2
)
return
;
if
(
!
h2
)
return
;
if
(
!
h1
)
{
if
(
!
h1
)
{
RHASH_TBL
(
hash1
)
=
kh_copy
(
ht
,
mrb
,
h2
);
RHASH_TBL
(
hash1
)
=
sg_copy
(
mrb
,
h2
);
return
;
return
;
}
}
for
(
k
=
kh_begin
(
h2
);
k
!=
kh_end
(
h2
);
k
++
)
{
sg_foreach
(
mrb
,
h2
,
merge_i
,
h1
);
khiter_t
k1
;
int
r
;
if
(
!
kh_exist
(
h2
,
k
))
continue
;
k1
=
kh_put2
(
ht
,
mrb
,
h1
,
kh_key
(
h2
,
k
),
&
r
);
kh_value
(
h1
,
k1
).
v
=
kh_value
(
h2
,
k
).
v
;
if
(
r
!=
0
)
{
/* expand */
kh_key
(
h1
,
k1
)
=
kh_key
(
h2
,
k
);
kh_value
(
h1
,
k1
).
n
=
kh_size
(
h1
)
-
1
;
}
}
mrb_write_barrier
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash1
));
mrb_write_barrier
(
mrb
,
(
struct
RBasic
*
)
RHASH
(
hash1
));
return
;
return
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment