From b9500933b891c12172f12fdb7a2f24f012f4ed51 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Wed, 20 Jun 2018 18:01:04 +0000 Subject: [PATCH] renamed SymbolSet to SymbolTable. added some exception classes to use when something is not found. renamed Set to AssociativeCollection and started writing a new Set class --- moo/kernel/Collect.moo | 163 ++++++++++++++++++++++++++++++++++------- moo/kernel/Except.moo | 21 ++++++ moo/lib/gc.c | 16 ++-- moo/lib/moo.h | 2 +- 4 files changed, 166 insertions(+), 36 deletions(-) diff --git a/moo/kernel/Collect.moo b/moo/kernel/Collect.moo index 356a9bb..ec0081b 100644 --- a/moo/kernel/Collect.moo +++ b/moo/kernel/Collect.moo @@ -351,16 +351,10 @@ class OrderedCollection(SequenceableCollection) method(#class) new: capacity { - ## super basicNew initWithCapacity: capacity. - ^super new initWithCapacity: capacity. + ^super new __init_with_capacity: capacity. } - ##method initialize - ##{ - ## ^super initialize. - ##} - - method initWithCapacity: capacity + method __init_with_capacity: capacity { self.buffer := Array new: capacity. self.firstIndex := capacity bitShift: -1. @@ -706,15 +700,128 @@ class Set(Collection) method(#class) new: size { - ^self new initialize: size. + ^self new __initialize_with_size: size. } method initialize { - ^self initialize: 128. (* TODO: default initial size *) + ^self __initialize_with_size: 128. (* TODO: default initial size *) } - method initialize: size + method __initialize_with_size: size + { + if (size <= 0) { size := 2 }. + self.tally := 0. + self.bucket := Array new: size. + } + + method __make_expanded_bucket: bs + { + | newbuc newsz ass index i | + + (* expand the bucket *) + newsz := bs + 128. + newbuc := Array new: newsz. + i := 0. + while (i < bs) + { + ass := self.bucket at: i. + if (ass notNil) + { + index := (ass hash) rem: newsz. + while ((newbuc at: index) notNil) { index := (index + 1) rem: newsz }. + newbuc at: index put: ass + }. + i := i + 1. + }. + + ^newbuc. + } + + method __find_index: anObject + { + | bs ass index | + + bs := self.bucket size. + index := (anObject hash) rem: bs. + + while ((ass := self.bucket at: index) notNil) + { + if (anObject = ass) { ^index }. + index := (index + 1) rem: bs. + }. + + ^index. ## the item at this index is nil. + } + + method add: anObject + { + | index absent bs | + if (anObject isNil) { ^anObject }. + + index := self __find_index: anObject. + absent := (self.bucket at: index) isNil. + self.bucket at: index put: anObject. + + if (absent) + { + self.tally := self.tally + 1. + bs := self.bucket size. + if (self.tally > (bs * 3 div: 4)) { self.bucket := self __make_expanded_bucket: bs }. + }. + ^anObject. + } + + method remove: oldObject ifAbsent: anExceptionBlock + { + } + + method includes: anObject + { + } + + method isEmpty + { + ^self.tally == 0 + } + + method = aSet + { + ifnot (self class == aSet class) { ^false }. + if (self == aSet){ ^true }. + ifnot (self.tally = aSet size) { ^false }. + self do: [ :el | ifnot (aSet includes: el) { ^false } ]. + ^true + } + + method do: aBlock + { + | bs i obj | + bs := self.bucket size. + i := 0. + while (i < bs) + { + if ((obj := self.bucket at: i) notNil) { aBlock value: obj }. + i := i + 1. + }. + } +} + +class AssociativeCollection(Collection) +{ + var tally, bucket. + + method(#class) new: size + { + ^self new __initialize_with_size: size. + } + + method initialize + { + ^self __initialize_with_size: 128. (* TODO: default initial size *) + } + + method __initialize_with_size: size { if (size <= 0) { size := 2 }. self.tally := 0. @@ -728,25 +835,27 @@ class Set(Collection) method __make_expanded_bucket: bs { - | newbuc newsz ass index | + | newbuc newsz ass index i | (* expand the bucket *) newsz := bs + 128. (* TODO: keep this growth policy in sync with VM(dic.c) *) newbuc := Array new: newsz. - 0 priorTo: bs do: [:i | + i := 0. + while (i < bs) + { ass := self.bucket at: i. if (ass notNil) { index := (ass key hash) rem: newsz. - while ((newbuc at: index) notNil) { index := (index + 1) rem: newsz }. + while ((newbuc at: index) notNil) { index := (index + 1) rem: newsz }. newbuc at: index put: ass }. - ]. + i := i + 1. + }. ^newbuc. } - - + method __find: key or_upsert: upsert with: value { | hv ass bs index ntally | @@ -781,7 +890,7 @@ class Set(Collection) ass := Association key: key value: value. self.tally := ntally. self.bucket at: index put: ass. - + ^ass } @@ -789,7 +898,7 @@ class Set(Collection) { | ass | ass := self __find: key or_upsert: false with: nil. - if (ass isError) { ^ass }. + if (ass isError) { ^KeyNotFoundException signal }. ^ass value } @@ -844,7 +953,7 @@ class Set(Collection) method __find_index: key { | bs ass index | - + bs := self.bucket size. index := (key hash) rem: bs. @@ -898,7 +1007,7 @@ class Set(Collection) { | index | index := self __find_index: key. - if (index isError) { ^index }. + if (index isError) { ^KeyNotFoundException signal. }. ^self __remove_at: index. } @@ -973,11 +1082,11 @@ class Set(Collection) } } -class SymbolSet(Set) +class SymbolTable(AssociativeCollection) { } -class Dictionary(Set) +class Dictionary(AssociativeCollection) { (* [NOTE] * VM require Dictionary to implement new: and __put_assoc @@ -1000,7 +1109,7 @@ class Dictionary(Set) * * it must return self for the way VM works. *) - method put_assoc: assoc + method __put_assoc: assoc { | hv ass bs index ntally key | @@ -1046,7 +1155,7 @@ class Dictionary(Set) (* Namespace is marked with #limited. If a compiler is writeen in moo itself, it must * call a primitive to instantiate a new namespace rather than sending the new message * to Namespace *) -class(#limited) Namespace(Set) +class(#limited) Namespace(AssociativeCollection) { var name, nsup. @@ -1073,11 +1182,11 @@ class(#limited) Namespace(Set) } } -class PoolDictionary(Set) +class PoolDictionary(AssociativeCollection) { } -class MethodDictionary(Dictionary) +class MethodDictionary(AssociativeCollection) { } diff --git a/moo/kernel/Except.moo b/moo/kernel/Except.moo index 2fc19e8..81864c0 100644 --- a/moo/kernel/Except.moo +++ b/moo/kernel/Except.moo @@ -454,6 +454,22 @@ class ProhibitedMessageException(Exception) { } +class NotFoundException(Exception) +{ +} + +class KeyNotFoundException(NotFoundException) +{ +} + +class ValueNotFoundException(NotFoundException) +{ +} + +class IndexNotFoundException(NotFoundException) +{ +} + extend Apex { method(#dual,#liberal) primitiveFailed(method) @@ -527,6 +543,11 @@ System logNl: '== END OF BACKTRACE =='. SubclassResponsibilityException signal: ('Subclass must implement ' & method_name). } + method(#dual) shouldNotImplement: method_name + { + SubclassResponsibilityException signal: ('Message should not be implemented - ' & method_name). + } + method(#dual) notImplemented: method_name { | class_name | diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 1b81706..65f9210 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -173,14 +173,14 @@ static kernel_class_info_t kernel_classes[] = MOO_OBJ_TYPE_BYTE, MOO_OFFSETOF(moo_t, _byte_array) }, - { 9, - { 'S','y','m','b','o','l','S','e','t' }, + { 11, + { 'S','y','m','b','o','l','T','a','b','l','e' }, 0, 0, MOO_DIC_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP, - MOO_OFFSETOF(moo_t, _symbol_set) }, + MOO_OFFSETOF(moo_t, _symbol_table) }, { 10, { 'D','i','c','t','i','o','n','a','r','y' }, @@ -468,7 +468,7 @@ static int ignite_2 (moo_t* moo) if (!moo->_true || !moo->_false) return -1; /* Create the symbol table */ - tmp = moo_instantiate (moo, moo->_symbol_set, MOO_NULL, 0); + tmp = moo_instantiate (moo, moo->_symbol_table, MOO_NULL, 0); if (!tmp) return -1; moo->symtab = (moo_oop_dic_t)tmp; @@ -478,18 +478,18 @@ static int ignite_2 (moo_t* moo) * The pointer 'moo->symtab; can change in moo_instantiate() and the * target address of assignment may get set before moo_instantiate() * is called. */ - tmp = moo_instantiate (moo, moo->_array, MOO_NULL, moo->option.dfl_symtab_size); + tmp = moo_instantiate(moo, moo->_array, MOO_NULL, moo->option.dfl_symtab_size); if (!tmp) return -1; moo->symtab->bucket = (moo_oop_oop_t)tmp; /* Create the system dictionary */ - tmp = (moo_oop_t)moo_makensdic (moo, moo->_namespace, moo->option.dfl_sysdic_size); + tmp = (moo_oop_t)moo_makensdic(moo, moo->_namespace, moo->option.dfl_sysdic_size); if (!tmp) return -1; moo->sysdic = (moo_oop_nsdic_t)tmp; /* Create a nil process used to simplify nil check in GC. * only accessible by VM. not exported via the global dictionary. */ - tmp = (moo_oop_t)moo_instantiate (moo, moo->_process, MOO_NULL, 0); + tmp = (moo_oop_t)moo_instantiate(moo, moo->_process, MOO_NULL, 0); if (!tmp) return -1; moo->nil_process = (moo_oop_process_t)tmp; moo->nil_process->sp = MOO_SMOOI_TO_OOP(-1); @@ -515,7 +515,7 @@ static int ignite_3 (moo_t* moo) /* Register kernel classes manually created so far to the system dictionary */ static moo_ooch_t str_processor[] = { 'P', 'r', 'o', 'c', 'e', 's', 's', 'o', 'r' }; static moo_ooch_t str_dicnew[] = { 'n', 'e', 'w', ':' }; - static moo_ooch_t str_dicputassoc[] = { 'p', 'u', 't', '_', 'a', 's', 's', 'o', 'c', ':' }; + static moo_ooch_t str_dicputassoc[] = { '_','_','p', 'u', 't', '_', 'a', 's', 's', 'o', 'c', ':' }; moo_oow_t i; moo_oop_t sym; diff --git a/moo/lib/moo.h b/moo/lib/moo.h index cc2a14b..9522b68 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1390,7 +1390,7 @@ struct moo_t moo_oop_class_t _symbol; /* Symbol */ moo_oop_class_t _array; /* Array */ moo_oop_class_t _byte_array; /* ByteArray */ - moo_oop_class_t _symbol_set; /* SymbolSet */ + moo_oop_class_t _symbol_table; /* SymbolTable */ moo_oop_class_t _dictionary; moo_oop_class_t _namespace; /* Namespace */