diff --git a/modules/Kernel/BareTests/BareTestsModule.st b/modules/Kernel/BareTests/BareTestsModule.st index 59f1aab6..bd8566b5 100644 --- a/modules/Kernel/BareTests/BareTestsModule.st +++ b/modules/Kernel/BareTests/BareTestsModule.st @@ -10,6 +10,13 @@ Class { #category : #'Powerlang-Core' } +{ #category : #spec } +BareTestsModule >> imports [ + ^{ + #Kernel -> #(HashTable) + } +] + { #category : #tests } BareTestsModule >> test001SendYourself [ ^true yourself @@ -385,6 +392,11 @@ BareTestsModule >> test232BitShiftRightSelector [ ^(16rAA00 bitShiftRight: 8) == 16rAA ] +{ #category : #tests } +BareTestsModule >> test240HashTablePrimeForReturnsNextGoodPrime [ + ^(HashTable primeFor: 300) == 359 +] + { #category : #main } BareTestsModule >> runTest: selector [ | result | @@ -434,7 +446,8 @@ BareTestsModule >> main: anArray [ test220BitXorSmallIntegers test221BitXorSmallIntWithLargeInt test222BitXorLargeIntWithSmallInt test230BitShiftLeftOverflow test231BitShiftRightNegativeArg - test232BitShiftRightSelector). + test232BitShiftRightSelector + test240HashTablePrimeForReturnsNextGoodPrime). tests do: [:sel | (self runTest: sel) ifTrue: [passed := passed + 1] diff --git a/modules/Kernel/HashTable.st b/modules/Kernel/HashTable.st index 95ca1943..10552564 100644 --- a/modules/Kernel/HashTable.st +++ b/modules/Kernel/HashTable.st @@ -91,7 +91,7 @@ HashTable class >> primeFor: size [ primes := self goodPrimes. 1 to: primes size do: [:i | | p | p := primes at: i. - p > n ifTrue: [p]]. + p > n ifTrue: [^p]]. ^n ] diff --git a/modules/Kernel/LMR/Float.st b/modules/Kernel/LMR/Float.st index 85ad028c..7f5a257c 100644 --- a/modules/Kernel/LMR/Float.st +++ b/modules/Kernel/LMR/Float.st @@ -128,7 +128,7 @@ LMRFloat >> basicAt: index [ { #category : #random } LMRFloat >> fractionPart [ - | new result |> + | new result | new := Float new. result := self _floatFractionPartInto: new. result == new ifTrue: [^result]. diff --git a/runtime/cpp/Allocator/AllocationZone.cpp b/runtime/cpp/Allocator/AllocationZone.cpp index 0205877d..add76205 100644 --- a/runtime/cpp/Allocator/AllocationZone.cpp +++ b/runtime/cpp/Allocator/AllocationZone.cpp @@ -201,7 +201,7 @@ HeapObject *AllocationZone::shallowCopyCommiting_(HeapObject *object) if (copy) return copy; - auto size = object->bodySizeInBytes(); + auto size = object->totalSizeInBytes(); if (size > GCHeap::LargeThreshold) { auto space = _heap->createLargeSpace_(size); diff --git a/runtime/cpp/Allocator/GCHeap.cpp b/runtime/cpp/Allocator/GCHeap.cpp index 03caaa01..c593feb6 100644 --- a/runtime/cpp/Allocator/GCHeap.cpp +++ b/runtime/cpp/Allocator/GCHeap.cpp @@ -50,11 +50,9 @@ GCSpace *Egg::GCHeap::createLargeSpace_(uintptr_t size) error_(std::string("Not enough memory to allocate ") + std::to_string(size) + "bytes"); auto limit = address + size; - auto space = GCSpace::allocatedAt_limit_(address, limit); + auto space = GCSpace::allocatedAt_limit_(address, limit, true); space->_name = "Large"; - space->_committedLimit = limit; - space->_softLimit = limit; this->addSpace_(space); _largeSpaces.push_back(space); return space; diff --git a/runtime/cpp/Allocator/GCSpace.cpp b/runtime/cpp/Allocator/GCSpace.cpp index 20d70e4a..eea421ae 100644 --- a/runtime/cpp/Allocator/GCSpace.cpp +++ b/runtime/cpp/Allocator/GCSpace.cpp @@ -93,12 +93,18 @@ uintptr_t GCSpace::allocateCommittingIfNeeded_(uint32_t size) { auto answer = _next; auto next = answer + size; - if (next <= _softLimit || this->commitMemoryUpTo_(next)) + if (next <= _softLimit) + { + _next = next; + return answer; + } + if (this->commitMemoryUpTo_(next)) { + _softLimit = _committedLimit; _next = next; return answer; } - else return 0; + return 0; } bool GCSpace::increaseSoftLimit_(uint32_t delta) diff --git a/runtime/cpp/Bootstrap/Bootstrapper.cpp b/runtime/cpp/Bootstrap/Bootstrapper.cpp index dd3c3689..623b8ded 100644 --- a/runtime/cpp/Bootstrap/Bootstrapper.cpp +++ b/runtime/cpp/Bootstrap/Bootstrapper.cpp @@ -614,6 +614,8 @@ void Bootstrapper::compileAndInstallMethod_(const Egg::string& source, HeapObjec // Transfer the compiled method to a heap object HeapObject* method = allocateSlots_(Offsets::MethodInstSize + literalCount); + method->beNamed(); + method->beArrayed(); // Set method's behavior to CompiledMethod's instance behavior Object* cmBehavior = _compiledMethodClass->slot(Offsets::SpeciesInstanceBehavior); diff --git a/runtime/cpp/Compiler/Parser/SSmalltalkParser.cpp b/runtime/cpp/Compiler/Parser/SSmalltalkParser.cpp index c598b053..3d8e9dbe 100644 --- a/runtime/cpp/Compiler/Parser/SSmalltalkParser.cpp +++ b/runtime/cpp/Compiler/Parser/SSmalltalkParser.cpp @@ -644,82 +644,106 @@ bool SSmalltalkParser::hasKeywordSelector() const { } SParseNode* SSmalltalkParser::literalArray() { - // Matches Smalltalk literalArray → arrayBody → arrayElement - uint32_t position = _token->position().start(); - std::vector elements; - - // Step past #( (or ( for nested arrays) + auto* array = arrayBody(); step(); - while (_token && !_token->is(')') && !_token->isEnd()) { - // arrayElement - if (_token->isLiteral()) { - elements.push_back(parseLiteralValue()); - } else if (_token->isName()) { - elements.push_back(pseudoLiteralValue()); - } else if (_token->isKeyword()) { - // literalKeyword: collect multi-part keyword symbol - Egg::string keyword = _token->value(); - step(); - while (_token && _token->isKeyword()) { - keyword += _token->value(); - step(); - } - elements.push_back(LiteralValue::fromSymbol(keyword)); - continue; // already stepped past last keyword - } else if (_token->is('-')) { - LiteralValue neg = negativeNumberOrBinary(); - if (!neg.isNone()) { - elements.push_back(std::move(neg)); - } else { - elements.push_back(LiteralValue::fromSymbol("-")); - } - } else if (_token->hasSymbol()) { - elements.push_back(LiteralValue::fromSymbol(_token->value())); - } else if (_token->is('(') || _token->is("#(")) { - // nested literal array - auto* nested = static_cast(literalArray()); - elements.push_back(nested->literalValue()); - continue; // literalArray already stepped past ) - } else if (_token->is("#[")) { - auto* nested = static_cast(literalByteArray()); - elements.push_back(nested->literalValue()); - continue; // literalByteArray already stepped past ] - } else { - error_("invalid literal array element"); - } + return array; +} + +SParseNode* SSmalltalkParser::literalByteArray() { + auto* node = byteArrayBody(); + step(); + return node; +} + +SLiteralNode* SSmalltalkParser::arrayBody() { + std::vector literals; + uint32_t position = _token->position().start(); + + while (true) { step(); + if (!_token || _token->is(')') || _token->isEnd()) { + break; + } + literals.push_back(arrayElement()); } - if (_token && _token->isEnd()) missingToken_(")"); + if (!_token || _token->isEnd()) { + missingToken_(")"); + } - auto lit = new SLiteralNode(_compiler); - lit->literalValue_(LiteralValue::fromArray(std::move(elements))); - lit->position_(Stretch(position, _token ? _token->position().end() : position)); - step(); // past ) - return lit; + auto* node = new SLiteralNode(_compiler); + node->literalValue_(LiteralValue::fromArray(std::move(literals))); + node->position_(Stretch(position, _token->position().end())); + return node; } -SParseNode* SSmalltalkParser::literalByteArray() { - uint32_t position = _token->position().start(); - step(); - std::vector bytes; - while (_token && !_token->is(']') && !_token->isEnd()) { - if (_token->isLiteral()) { - // Each element should be a number 0-255 - std::string v = _token->value().toUtf8(); - int val = static_cast(std::stol(v, nullptr, 0)); - bytes.push_back(static_cast(val)); +LiteralValue SSmalltalkParser::arrayElement() { + if (_token->isLiteral()) { + return parseLiteralValue(); + } + if (_token->isName()) { + return pseudoLiteralValue(); + } + if (_token->isKeyword()) { + return literalKeyword(); + } + if (_token->is('-')) { + LiteralValue neg = negativeNumberOrBinary(); + return neg.isNone() ? LiteralValue::fromSymbol("-") : std::move(neg); + } + if (_token->hasSymbol()) { + return LiteralValue::fromSymbol(_token->value()); + } + if (_token->is('(') || _token->is("#(")) { + return arrayBody()->literalValue(); + } + if (_token->is("#[")) { + return byteArrayBody()->literalValue(); + } + error_("invalid literal array element"); + return LiteralValue(); +} + +LiteralValue SSmalltalkParser::literalKeyword() { + Egg::string keyword = _token->value(); + uint32_t prevEnd = _token->position().end(); + + while (true) { + auto* nextToken = peek(); + if (!nextToken || !nextToken->isKeyword() || nextToken->position().start() != prevEnd) { + break; } step(); + keyword += _token->value(); + prevEnd = _token->position().end(); } + + return LiteralValue::fromSymbol(keyword); +} + +SLiteralNode* SSmalltalkParser::byteArrayBody() { + std::vector bytes; + uint32_t position = _token->position().start(); + + while (true) { + step(); + if (!_token || !_token->isLiteral()) { + break; + } + + std::string v = _token->value().toUtf8(); + int val = static_cast(std::stol(v, nullptr, 0)); + bytes.push_back(static_cast(val)); + } + if (!_token || !_token->is(']')) { missingToken_("]"); } - auto lit = new SLiteralNode(_compiler); - lit->literalValue_(LiteralValue::fromByteArray(std::move(bytes))); - lit->position_(Stretch(position, _token->position().end())); - step(); - return lit; + + auto* node = new SLiteralNode(_compiler); + node->literalValue_(LiteralValue::fromByteArray(std::move(bytes))); + node->position_(Stretch(position, _token->position().end())); + return node; } SBraceNode* SSmalltalkParser::bracedArray() { diff --git a/runtime/cpp/Compiler/Parser/SSmalltalkParser.h b/runtime/cpp/Compiler/Parser/SSmalltalkParser.h index 051b8ba0..2a519e79 100644 --- a/runtime/cpp/Compiler/Parser/SSmalltalkParser.h +++ b/runtime/cpp/Compiler/Parser/SSmalltalkParser.h @@ -89,6 +89,10 @@ class SSmalltalkParser { SParseNode* literalArray(); SParseNode* literalByteArray(); + SLiteralNode* arrayBody(); + LiteralValue arrayElement(); + LiteralValue literalKeyword(); + SLiteralNode* byteArrayBody(); SBraceNode* bracedArray(); LiteralValue parseLiteralValue(); diff --git a/runtime/cpp/Compiler/tests/ParserTest.cpp b/runtime/cpp/Compiler/tests/ParserTest.cpp index 6a349d5f..199af53c 100644 --- a/runtime/cpp/Compiler/tests/ParserTest.cpp +++ b/runtime/cpp/Compiler/tests/ParserTest.cpp @@ -423,6 +423,110 @@ TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal string", "[parser tearDown(); } +TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal array", "[parser]") { + setUp(); + + SMethodNode* method = parseExpression("#(16rFE $a 'hello' #s #(1 2))"); + + REQUIRE(method != nullptr); + REQUIRE(method->statements().size() == 1); + + SParseNode* stmt = method->statements()[0]; + REQUIRE(stmt->isLiteral()); + + SLiteralNode* lit = static_cast(stmt); + const LiteralValue& array = lit->literalValue(); + REQUIRE(array.isArray()); + REQUIRE(array.asArray().size() == 5); + + REQUIRE(array.asArray()[0].isInteger()); + REQUIRE(array.asArray()[0].asInteger() == 0xFE); + REQUIRE(array.asArray()[1].isCharacter()); + REQUIRE(array.asArray()[1].asCharacter() == 'a'); + REQUIRE(array.asArray()[2].isString()); + REQUIRE(array.asArray()[2].asString() == "hello"); + REQUIRE(array.asArray()[3].isSymbol()); + REQUIRE(array.asArray()[3].asString() == "s"); + REQUIRE(array.asArray()[4].isArray()); + REQUIRE(array.asArray()[4].asArray().size() == 2); + REQUIRE(array.asArray()[4].asArray()[0].asInteger() == 1); + REQUIRE(array.asArray()[4].asArray()[1].asInteger() == 2); + + tearDown(); +} + +TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal keyword array symbols", "[parser]") { + setUp(); + + SMethodNode* method = parseExpression("#(a:b: c: d:)"); + + REQUIRE(method != nullptr); + REQUIRE(method->statements().size() == 1); + + SParseNode* stmt = method->statements()[0]; + REQUIRE(stmt->isLiteral()); + + SLiteralNode* lit = static_cast(stmt); + const LiteralValue& array = lit->literalValue(); + REQUIRE(array.isArray()); + REQUIRE(array.asArray().size() == 3); + + REQUIRE(array.asArray()[0].isSymbol()); + REQUIRE(array.asArray()[0].asString() == "a:b:"); + REQUIRE(array.asArray()[1].isSymbol()); + REQUIRE(array.asArray()[1].asString() == "c:"); + REQUIRE(array.asArray()[2].isSymbol()); + REQUIRE(array.asArray()[2].asString() == "d:"); + + tearDown(); +} + +TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Negative elements in literal array", "[parser]") { + setUp(); + + SMethodNode* method = parseExpression("#(-21 1 -5 4)"); + + REQUIRE(method != nullptr); + REQUIRE(method->statements().size() == 1); + + SParseNode* stmt = method->statements()[0]; + REQUIRE(stmt->isLiteral()); + + SLiteralNode* lit = static_cast(stmt); + const LiteralValue& array = lit->literalValue(); + REQUIRE(array.isArray()); + REQUIRE(array.asArray().size() == 4); + REQUIRE(array.asArray()[0].asInteger() == -21); + REQUIRE(array.asArray()[1].asInteger() == 1); + REQUIRE(array.asArray()[2].asInteger() == -5); + REQUIRE(array.asArray()[3].asInteger() == 4); + + tearDown(); +} + +TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Dash-starting symbols in literal array", "[parser]") { + setUp(); + + SMethodNode* method = parseExpression("#(#++ #--)"); + + REQUIRE(method != nullptr); + REQUIRE(method->statements().size() == 1); + + SParseNode* stmt = method->statements()[0]; + REQUIRE(stmt->isLiteral()); + + SLiteralNode* lit = static_cast(stmt); + const LiteralValue& array = lit->literalValue(); + REQUIRE(array.isArray()); + REQUIRE(array.asArray().size() == 2); + REQUIRE(array.asArray()[0].isSymbol()); + REQUIRE(array.asArray()[0].asString() == "++"); + REQUIRE(array.asArray()[1].isSymbol()); + REQUIRE(array.asArray()[1].asString() == "--"); + + tearDown(); +} + TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Complex expression", "[parser]") { setUp(); diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index 569b0a5c..e2f7286e 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -952,11 +952,16 @@ Object* Evaluator::primitiveHostLoadModule() { Object* Evaluator::primitiveHostWriteFile() { auto filename = this->_context->firstArgument()->asHeapObject()->asLocalString(); - auto contents = this->_context->secondArgument()->asHeapObject()->asLocalString(); + auto contents = this->_context->secondArgument()->asHeapObject(); + if (!contents->isBytes()) + return this->failPrimitive(); + bool isString = _runtime->speciesOf_((Object*)contents) == _runtime->_stringClass; + auto byteCount = contents->size(); + if (isString && byteCount > 0) byteCount -= 1; // strip String null terminator std::ofstream file(filename, std::ios::binary); if (!file) return this->failPrimitive(); - file.write(contents.data(), contents.size()); + file.write((const char*)contents, byteCount); return (Object*)this->_context->self(); } @@ -1174,14 +1179,40 @@ Object* Evaluator::primitivePrimeFor() { } Object* Evaluator::primitivePrimeFor_(auto anInteger) { - int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 269, 359, 479, 641, 857, 1151, 1549, 2069, 2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539, 3727, 3911, 4441, 4787, 5119, 5471, 5801, 6143, 6521, 6827, 7177, 7517, 7853, 8783, 9601, 10243, 10867, 11549, 12239, 12919, 13679, 14293, 15013, 15731, 17569, 19051, 20443, 21767, 23159, 24611, 25847, 27397, 28571, 30047, 31397, 35771, 38201, 40841, 43973, 46633, 48989, 51631, 54371, 57349, 60139, 62969}; + // Table matches HashTable>>goodPrimes in Smalltalk (covers up to ~1.07 billion). + static const int primes[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, + 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, + 269, 359, 479, 641, 857, 1151, 1549, 2069, + 2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539, 3727, 3911, + 4441, 4787, 5119, 5471, 5801, 6143, 6521, 6827, 7177, 7517, 7853, + 8783, 9601, 10243, 10867, 11549, 12239, 12919, 13679, 14293, 15013, 15731, + 17569, 19051, 20443, 21767, 23159, 24611, 25847, 27397, 28571, 30047, 31397, + 35771, 38201, 40841, 43973, 46633, 48989, 51631, 54371, 57349, 60139, 62969, + 70589, 76091, 80347, 85843, 90697, 95791, 101051, 106261, 111143, 115777, 120691, 126311, + 140863, 150523, 160969, 170557, 181243, 190717, 201653, 211891, 221251, 232591, 242873, 251443, + 282089, 300869, 321949, 341227, 362353, 383681, 401411, 422927, 443231, 464951, 482033, 504011, + 562621, 605779, 647659, 681607, 723623, 763307, 808261, 844709, 886163, 926623, 967229, 1014617, + 1121987, 1201469, 1268789, 1345651, 1429531, 1492177, 1577839, 1651547, 1722601, 1800377, 1878623, 1942141, 2028401, + 2242727, 2399581, 2559173, 2686813, 2836357, 3005579, 3144971, 3283993, 3460133, 3582923, 3757093, 3903769, 4061261, + 4455361, 4783837, 5068529, 5418079, 5680243, 6000023, 6292981, 6611497, 6884641, 7211599, 7514189, 7798313, 8077189, + 9031853, 9612721, 10226107, 10745291, 11338417, 11939203, 12567671, 13212697, 13816333, 14337529, 14938571, 15595673, 16147291, + 17851577, 18993941, 20180239, 21228533, 22375079, 23450491, 24635579, 25683871, 26850101, 27921689, 29090911, 30153841, 31292507, 32467307, + 35817611, 37983761, 40234253, 42457253, 44750177, 46957969, 49175831, 51442639, 53726417, 55954637, 58126987, 60365939, 62666977, 64826669, + 71582779, 76039231, 80534381, 84995153, 89500331, 93956777, 98470819, 102879613, 107400389, 111856841, 116365721, 120819287, 125246581, 129732203, + 143163379, 152076289, 161031319, 169981667, 179000669, 187913573, 196826447, 205826729, 214748357, 223713691, 232679021, 241591901, 250504801, 259470131, + 285162679, 301939921, 318717121, 335494331, 352271573, 369148753, 385926017, 402603193, 419480419, 436157621, 453034849, 469712051, 486589307, 503366497, 520043707, + 570475349, 603929813, 637584271, 671138659, 704693081, 738247541, 771801929, 805356457, 838910803, 872365267, 905919671, 939574117, 973128521, 1006682977, 1040137411, + 1073741833 + }; - for (int i = 0; i < sizeof(primes); i++) { + for (int i = 0; i < (int)(sizeof(primes) / sizeof(primes[0])); i++) { auto prime = primes[i]; if (prime >= anInteger) return newIntObject(prime); } - return (Object*)this->_runtime->_nilObj; + return failPrimitive(); // fall back to Smalltalk for values > 1073741833 } Object* Evaluator::primitiveSMIBitAnd() { diff --git a/runtime/cpp/Evaluator/Runtime.cpp b/runtime/cpp/Evaluator/Runtime.cpp index b6ef13a5..05be1933 100644 --- a/runtime/cpp/Evaluator/Runtime.cpp +++ b/runtime/cpp/Evaluator/Runtime.cpp @@ -20,7 +20,7 @@ Runtime::Runtime(Loader* loader, ImageSegment* kernel, SymbolProvider* symbolPro _loader(loader), _kernel(kernel), _symbolProvider(symbolProvider), - _lastHash(0) + _lastHash(1) // LFSR seed; must be non-zero (0 is a fixed point). { debugRuntime = this; this->initializeKernelObjects(); diff --git a/runtime/cpp/Evaluator/Runtime.h b/runtime/cpp/Evaluator/Runtime.h index c16cf6c6..cc628a8d 100644 --- a/runtime/cpp/Evaluator/Runtime.h +++ b/runtime/cpp/Evaluator/Runtime.h @@ -110,15 +110,11 @@ class Runtime { uintptr_t hashFor_(Object *anObject); - int16_t nextHash() { - auto prev = this->_lastHash; - auto shifted = this->_lastHash >> 1; - this->_lastHash = (this->_lastHash & 1) == 0 ? shifted : shifted ^ 0xB9C8; - if (this->_lastHash == 0) { - return prev; - } - return this->_lastHash; - } + uint16_t nextHash() { + uint16_t shifted = _lastHash >> 1; + _lastHash = (_lastHash & 1) == 0 ? shifted : shifted ^ 0xB9C8; + return _lastHash; + } void registerCache_for_(SAbstractMessage *message, Object *symbol) { auto it = _inlineCaches.find(symbol); diff --git a/runtime/cpp/HeapObject.h b/runtime/cpp/HeapObject.h index 304a2430..40c8adbe 100644 --- a/runtime/cpp/HeapObject.h +++ b/runtime/cpp/HeapObject.h @@ -202,7 +202,8 @@ struct HeapObject uint32_t bodySizeInBytes() const; // the size in bytes of the buffer used for the body of this object (buffer sizes are aligned to pointer size) uint32_t bodySizeInSlots() const; // the size in slots of the buffer used for the body of this object (buffer sizes are aligned to pointer size) uint32_t headerSizeInBytes() const; // 8 or 16 depending if the object is small or large - + uint32_t totalSizeInBytes() const { return this->headerSizeInBytes() + this->bodySizeInBytes(); }; + uint32_t pointersSize() const ; // bodySizeInSlots if the object is marked as slots, 0 if marked as bytes uint32_t strongPointersSize() const;