Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,9 +1,9 @@ OBJFW_SHARED_LIB = @OBJFW_SHARED_LIB@ OBJFW_STATIC_LIB = @OBJFW_STATIC_LIB@ -OBJFW_LIB_MAJOR = 5 -OBJFW_LIB_MINOR = 1 +OBJFW_LIB_MAJOR = 6 +OBJFW_LIB_MINOR = 0 OBJFW_LIB_MAJOR_MINOR = ${OBJFW_LIB_MAJOR}.${OBJFW_LIB_MINOR} ASPRINTF_M = @ASPRINTF_M@ ATOMIC_H = @ATOMIC_H@ BIN_PREFIX = @BIN_PREFIX@ Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -374,20 +374,10 @@ * * \return A description for the class, which is usually the class name */ + (OFString*)description; -/** - * \brief Replaces a class method implementation with another implementation. - * - * \param newImp The new implementation for the class method - * \param selector The selector of the class method to replace - * \return The old implementation - */ -+ (IMP)setImplementation: (IMP)newImp - forClassMethod: (SEL)selector; - /** * \brief Replaces a class method with a class method from another class. * * \param selector The selector of the class method to replace * \param class_ The class from which the new class method should be taken @@ -394,21 +384,10 @@ * \return The old implementation */ + (IMP)replaceClassMethod: (SEL)selector withMethodFromClass: (Class)class_; -/** - * \brief Replaces an instance method implementation with another - * implementation. - * - * \param newImp The new implementation for the instance method - * \param selector The selector of the instance method to replace - * \return The old implementation - */ -+ (IMP)setImplementation: (IMP)newImp - forInstanceMethod: (SEL)selector; - /** * \brief Replaces an instance method with an instance method from another * class. * * \param selector The selector of the instance method to replace @@ -417,40 +396,40 @@ */ + (IMP)replaceInstanceMethod: (SEL)selector withMethodFromClass: (Class)class_; /** - * \brief Adds a class method to the class. - * - * If the method already exists, nothing is done and NO is returned. If you want - * to change the implementation of a method, use - * setImplementation:forClassMethod:. - * - * \param selector The selector for the new method - * \param typeEncoding The type encoding for the new method - * \param implementation The implementation for the new method - * \return Whether the method has been added - */ -+ (BOOL)addClassMethod: (SEL)selector - withTypeEncoding: (const char*)typeEncoding - implementation: (IMP)implementation; - -/** - * \brief Adds an instance method to the class. - * - * If the method already exists, nothing is done and NO is returned. If you want - * to change the implementation of a method, use - * setImplementation:forInstanceMethod:. - * - * \param selector The selector for the new method - * \param typeEncoding The type encoding for the new method - * \param implementation The implementation for the new method - * \return Whether the method has been added - */ -+ (BOOL)addInstanceMethod: (SEL)selector - withTypeEncoding: (const char*)typeEncoding - implementation: (IMP)implementation; + * \brief Replaces or adds a class method. + * + * If the method already exists, it is replaced and the old implementation + * returned. If the method does not exist, it is added with the specified type + * encoding. + * + * \param selector The selector for the new method + * \param implementation The implementation for the new method + * \param typeEncoding The type encoding for the new method + * \return The old implementation or nil if the method was added + */ ++ (IMP)replaceClassMethod: (SEL)selector + withImplementation: (IMP)implementation + typeEncoding: (const char*)typeEncoding; + +/** + * \brief Replaces or adds an instance method. + * + * If the method already exists, it is replaced and the old implementation + * returned. If the method does not exist, it is added with the specified type + * encoding. + * + * \param selector The selector for the new method + * \param implementation The implementation for the new method + * \param typeEncoding The type encoding for the new method + * \return The old implementation or nil if the method was added + */ ++ (IMP)replaceInstanceMethod: (SEL)selector + withImplementation: (IMP)implementation + typeEncoding: (const char*)typeEncoding; /** * \brief Adds all methods from the specified class to the class that is the * receiver. * Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -365,172 +365,66 @@ + (OFString*)description { return [self className]; } -+ (IMP)setImplementation: (IMP)newImp - forClassMethod: (SEL)selector -{ -#if defined(OF_OBJFW_RUNTIME) - if (newImp == (IMP)0 || !class_respondsToSelector(self->isa, selector)) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - return objc_replace_class_method(self, selector, newImp); -#elif defined(OF_OLD_GNU_RUNTIME) - Method_t method; - MethodList_t iter; - - method = class_get_class_method(self->class_pointer, selector); - - if (newImp == (IMP)0 || method == METHOD_NULL) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - for (iter = ((Class)self->class_pointer)->methods; iter != NULL; - iter = iter->method_next) { - int i; - - for (i = 0; i < iter->method_count; i++) - if (sel_eq(iter->method_list[i].method_name, - selector)) { - IMP oldImp; - - oldImp = iter->method_list[i].method_imp; - iter->method_list[i].method_imp = newImp; - - __objc_update_dispatch_table_for_class( - (Class)self->class_pointer); - - return oldImp; - } - } - - assert([self addClassMethod: selector - withTypeEncoding: method->method_types - implementation: newImp]); - - return (IMP)0; -#else - Method method; - - if (newImp == (IMP)0 || - (method = class_getClassMethod(self, selector)) == NULL) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - /* - * Cast needed because it's isa in the Apple runtime, but class_pointer - * in the GNU runtime. - */ - return class_replaceMethod(((OFObject*)self)->isa, selector, newImp, - method_getTypeEncoding(method)); -#endif -} - + (IMP)replaceClassMethod: (SEL)selector withMethodFromClass: (Class)class { IMP newImp; - - if (![class isSubclassOfClass: self]) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; + const char *typeEncoding; newImp = [class methodForSelector: selector]; - - return [self setImplementation: newImp - forClassMethod: selector]; -} - -+ (IMP)setImplementation: (IMP)newImp - forInstanceMethod: (SEL)selector -{ -#if defined(OF_OBJFW_RUNTIME) - if (newImp == (IMP)0 || !class_respondsToSelector(self, selector)) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - return objc_replace_instance_method(self, selector, newImp); -#elif defined(OF_OLD_GNU_RUNTIME) - Method_t method; - MethodList_t iter; - - method = class_get_instance_method(self, selector); - - if (newImp == (IMP)0 || method == METHOD_NULL) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - for (iter = ((Class)self)->methods; iter != NULL; - iter = iter->method_next) { - int i; - - for (i = 0; i < iter->method_count; i++) - if (sel_eq(iter->method_list[i].method_name, - selector)) { - IMP oldImp; - - oldImp = iter->method_list[i].method_imp; - iter->method_list[i].method_imp = newImp; - - __objc_update_dispatch_table_for_class(self); - - return oldImp; - } - } - - assert([self addInstanceMethod: selector - withTypeEncoding: method->method_types - implementation: newImp]); - - return (IMP)0; -#else - Method method; - - if (newImp == (IMP)0 || - (method = class_getInstanceMethod(self, selector)) == NULL) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; - - return class_replaceMethod(self, selector, newImp, - method_getTypeEncoding(method)); -#endif + typeEncoding = [class typeEncodingForSelector: selector]; + + return [self replaceClassMethod: selector + withImplementation: newImp + typeEncoding: typeEncoding]; } + (IMP)replaceInstanceMethod: (SEL)selector withMethodFromClass: (Class)class { IMP newImp; - - if (![class isSubclassOfClass: self]) - @throw [OFInvalidArgumentException exceptionWithClass: self - selector: _cmd]; + const char *typeEncoding; newImp = [class instanceMethodForSelector: selector]; + typeEncoding = [class typeEncodingForInstanceSelector: selector]; - return [self setImplementation: newImp - forInstanceMethod: selector]; + return [self replaceInstanceMethod: selector + withImplementation: newImp + typeEncoding: typeEncoding]; } -+ (BOOL)addInstanceMethod: (SEL)selector - withTypeEncoding: (const char*)typeEncoding - implementation: (IMP)implementation ++ (IMP)replaceInstanceMethod: (SEL)selector + withImplementation: (IMP)implementation + typeEncoding: (const char*)typeEncoding { #if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME) - return class_addMethod(self, selector, implementation, typeEncoding); + return class_replaceMethod(self, selector, implementation, + typeEncoding); #elif defined(OF_OLD_GNU_RUNTIME) MethodList_t methodList; for (methodList = ((Class)self)->methods; methodList != NULL; methodList = methodList->method_next) { int i; - for (i = 0; i < methodList->method_count; i++) + for (i = 0; i < methodList->method_count; i++) { if (sel_eq(methodList->method_list[i].method_name, - selector)) - return NO; + selector)) { + IMP oldImp; + oldImp = methodList->method_list[i].method_imp; + + methodList->method_list[i].method_imp = + implementation; + + __objc_update_dispatch_table_for_class(self); + + return oldImp; + } + } } if ((methodList = malloc(sizeof(*methodList))) == NULL) @throw [OFOutOfMemoryException exceptionWithClass: self @@ -545,35 +439,46 @@ ((Class)self)->methods = methodList; __objc_update_dispatch_table_for_class(self); - return YES; + return (IMP)nil; #else @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; #endif } -+ (BOOL)addClassMethod: (SEL)selector - withTypeEncoding: (const char*)typeEncoding - implementation: (IMP)implementation ++ (IMP)replaceClassMethod: (SEL)selector + withImplementation: (IMP)implementation + typeEncoding: (const char*)typeEncoding { #if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME) - return class_addMethod(((OFObject*)self)->isa, selector, implementation, - typeEncoding); + return class_replaceMethod(((OFObject*)self)->isa, selector, + implementation, typeEncoding); #elif defined(OF_OLD_GNU_RUNTIME) MethodList_t methodList; for (methodList = ((Class)self->class_pointer)->methods; methodList != NULL; methodList = methodList->method_next) { int i; - for (i = 0; i < methodList->method_count; i++) + for (i = 0; i < methodList->method_count; i++) { if (sel_eq(methodList->method_list[i].method_name, - selector)) - return NO; + selector)) { + IMP oldImp; + oldImp = methodList->method_list[i].method_imp; + + methodList->method_list[i].method_imp = + implementation; + + __objc_update_dispatch_table_for_class( + (Class)self->class_pointer); + + return oldImp; + } + } } if ((methodList = malloc(sizeof(*methodList))) == NULL) @throw [OFOutOfMemoryException exceptionWithClass: self @@ -588,11 +493,11 @@ ((Class)self->class_pointer)->methods = methodList; __objc_update_dispatch_table_for_class((Class)self->class_pointer); - return YES; + return (IMP)nil; #else @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; #endif } @@ -610,62 +515,39 @@ methodList = class_copyMethodList(((OFObject*)class)->isa, &count); @try { for (i = 0; i < count; i++) { SEL selector = method_getName(methodList[i]); - IMP implementation; /* * Don't replace methods implemented in receiving class. */ if ([self methodForSelector: selector] != [superclass methodForSelector: selector]) continue; - implementation = [class methodForSelector: selector]; - - if ([self respondsToSelector: selector]) - [self setImplementation: implementation - forClassMethod: selector]; - else { - const char *typeEncoding = - method_getTypeEncoding(methodList[i]); - [self addClassMethod: selector - withTypeEncoding: typeEncoding - implementation: implementation]; - } + [self replaceClassMethod: selector + withMethodFromClass: class]; } } @finally { free(methodList); } methodList = class_copyMethodList(class, &count); @try { for (i = 0; i < count; i++) { SEL selector = method_getName(methodList[i]); - IMP implementation; /* * Don't replace methods implemented in receiving class. */ if ([self instanceMethodForSelector: selector] != [superclass instanceMethodForSelector: selector]) continue; - implementation = - [class instanceMethodForSelector: selector]; - - if ([self instancesRespondToSelector: selector]) - [self setImplementation: implementation - forInstanceMethod: selector]; - else { - const char *typeEncoding = - method_getTypeEncoding(methodList[i]); - [self addInstanceMethod: selector - withTypeEncoding: typeEncoding - implementation: implementation]; - } + [self replaceInstanceMethod: selector + withMethodFromClass: class]; } } @finally { free(methodList); } #elif defined(OF_OLD_GNU_RUNTIME) @@ -675,62 +557,39 @@ methodList != NULL; methodList = methodList->method_next) { int i; for (i = 0; i < methodList->method_count; i++) { SEL selector = methodList->method_list[i].method_name; - IMP implementation; /* * Don't replace methods implemented in receiving class. */ if ([self methodForSelector: selector] != [superclass methodForSelector: selector]) continue; - implementation = [class methodForSelector: selector]; - - if ([self respondsToSelector: selector]) - [self setImplementation: implementation - forClassMethod: selector]; - else { - const char *typeEncoding = - methodList->method_list[i].method_types; - [self addClassMethod: selector - withTypeEncoding: typeEncoding - implementation: implementation]; - } + [self replaceClassMethod: selector + withMethodFromClass: class]; } } for (methodList = class->methods; methodList != NULL; methodList = methodList->method_next) { int i; for (i = 0; i < methodList->method_count; i++) { SEL selector = methodList->method_list[i].method_name; - IMP implementation; /* * Don't replace methods implemented in receiving class. */ if ([self instanceMethodForSelector: selector] != [superclass instanceMethodForSelector: selector]) continue; - implementation = - [class instanceMethodForSelector: selector]; - - if ([self instancesRespondToSelector: selector]) - [self setImplementation: implementation - forInstanceMethod: selector]; - else { - const char *typeEncoding = - methodList->method_list[i].method_types; - [self addInstanceMethod: selector - withTypeEncoding: typeEncoding - implementation: implementation]; - } + [self replaceInstanceMethod: selector + withMethodFromClass: class]; } } #else @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd];