// Uses object identity to locate the next occurrence of the argument in the receiver from // the specified index to the specified index Oop* __fastcall Interpreter::primitiveStringSearch() { Oop* const sp = m_registers.m_stackPointer; Oop integerPointer = *sp; if (!ObjectMemoryIsIntegerObject(integerPointer)) return primitiveFailure(0); // startingAt not an integer const SMALLINTEGER startingAt = ObjectMemoryIntegerValueOf(integerPointer); Oop oopSubString = *(sp-1); BytesOTE* oteReceiver = reinterpret_cast<BytesOTE*>(*(sp-2)); if (ObjectMemory::fetchClassOf(oopSubString) != oteReceiver->m_oteClass) return primitiveFailure(2); // We know it can't be a SmallInteger because it has the same class as the receiver BytesOTE* oteSubString = reinterpret_cast<BytesOTE*>(oopSubString); VariantByteObject* bytesPattern = oteSubString->m_location; VariantByteObject* bytesReceiver = oteReceiver->m_location; const int M = oteSubString->bytesSize(); const int N = oteReceiver->bytesSize(); // Check 'startingAt' is in range if (startingAt < 1 || startingAt > N) return primitiveFailure(1); // out of bounds int nOffset = M == 0 || ((startingAt + M) - 1 > N) ? -1 : stringSearch(bytesReceiver->m_fields, N, bytesPattern->m_fields, M, startingAt - 1); *(sp-2) = ObjectMemoryIntegerObjectOf(nOffset+1); return sp-2; }
void testLargeTextsMatch(){ char T[1000]; char P[100]; for ( int i = 0; i<1000; i++ ){ T[i] = (i+i%99)%101; } for ( int i = 0; i<100; i++ ){ P[i] = T[i+900]; } int res = stringSearch( T, 1000, P, 100 ); TT_assert_EQ( 900, res ); }
void testLongerPattern(){ int res = stringSearch( "ab", 2, "abc", 3 ); TT_assert_EQ( -1, res ); }
void testEmptyText(){ int res = stringSearch( "", 0, "1", 1 ); TT_assert_EQ( -1, res ); }
void testEmptyPattern(){ int res = stringSearch( "123", 3, "", 0 ); TT_assert_EQ( 0, res ); }
void testSmallPatternMismatch2(){ int res = stringSearch( "abcd", 4, "abcc", 4 ); TT_assert_EQ( -1, res ); }
void testSmallPatternMatch3(){ int res = stringSearch( "abcd", 4, "bcd", 3 ); TT_assert_EQ( 1, res ); }
void testSmallPatternMatch(){ int res = stringSearch( "abcd", 4, "ab", 2 ); TT_assert_EQ( 0, res ); }
void testSmallTextMatch2(){ int res = stringSearch( "abcd", 4, "c", 1 ); TT_assert_EQ( 2, res ); }
void testSmallTextMatch(){ int res = stringSearch( "ab", 2, "b", 1 ); TT_assert_EQ( 1, res ); }
void testSimpleMismatch(){ int res = stringSearch( "a", 1, "b", 1 ); TT_assert_EQ( -1, res ); }
void testSimpleMatch(){ int res = stringSearch( "a", 1, "a", 1 ); TT_assert_EQ( 0, res ); }
void testMediumMatch2(){ int res = stringSearch( "ababcababababc", 14, "abababc", 7 ); TT_assert_EQ( 7, res ); }
void testMediumMatch(){ int res = stringSearch( "ababababababc", 13, "abababc", 7 ); TT_assert_EQ( 6, res ); }
CompletionType evaluate() { Register<Value> value; switch (method) { case ToString: case ValueOf: if (!getThis()->isObject()) { throw getErrorInstance("TypeError"); } value = static_cast<ObjectValue*>(getThis())->getValueProperty(); if (!value->isString()) { throw getErrorInstance("TypeError"); } break; case CharAt: value = charAt(); break; case CharCodeAt: value = charCodeAt(); break; case Concat: value = concat(getThis()); break; case IndexOf: value = indexOf(getThis()); break; case LastIndexOf: value = lastIndexOf(getThis()); break; case LocaleCompare: value = localeCompare(getThis()); break; case Match: value = stringMatch(); break; case Replace: value = stringReplace(); break; case Search: value = stringSearch(); break; case Slice: value = slice(getThis()); break; case Split: value = stringSplit(); break; case Substring: value = substring(getThis()); break; case Substr: value = substr(getThis()); break; case ToLowerCase: case ToLocaleLowerCase: value = toLowerCase(getThis()); break; case ToUpperCase: case ToLocaleUpperCase: value = toUpperCase(getThis()); break; } return CompletionType(CompletionType::Return, value, ""); }