Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -170,10 +170,12 @@ OFMutableSet_hashtable.m \ OFMutableString_UTF8.m \ OFSet_hashtable.m \ OFString_UTF8.m \ OFValue_bytes.m \ + OFValue_nonretainedObject.m \ + OFValue_pointer.m \ ${AUTORELEASE_M} \ ${FOUNDATION_COMPAT_M} \ ${INSTANCE_M} SRCS_FILES += OFSettings_INIFile.m \ OFURLHandler_file.m Index: src/OFValue.h ================================================================== --- src/OFValue.h +++ src/OFValue.h @@ -26,11 +26,25 @@ */ @interface OFValue: OFObject /*! * @brief The ObjC type encoding of the value. */ -@property (nonatomic, readonly) const char *objCType; +@property (readonly, nonatomic) const char *objCType; + +/*! + * @brief The value as a pointer to void. + * + * If the value is not pointer-sized, @ref OFInvalidFormatException is thrown. + */ +@property (readonly, nonatomic) void *pointerValue; + +/*! + * @brief The value as a non-retained object. + * + * If the value is not pointer-sized, @ref OFInvalidFormatException is thrown. + */ +@property (readonly, nonatomic) id nonretainedObjectValue; /*! * @brief Creates a new, autorelease OFValue with the specified bytes of the * specified type. * @@ -39,10 +53,32 @@ * @return A new, autoreleased OFValue */ + (instancetype)valueWithBytes: (const void *)bytes objCType: (const char *)objCType; +/*! + * @brief Creates a new, autoreleased OFValue containing the specified pointer. + * + * Only the raw value of the pointer is stored and no data will be copied. + * + * @param pointer The pointer the OFValue should contain + * @return A new, autoreleased OFValue + */ ++ (instancetype)valueWithPointer: (const void *)pointer; + +/*! + * @brief Creates a new, autoreleased OFValue containing the specified + * non-retained object. + * + * The object is not retained, which makes this useful for storing objects in + * collections without retaining them. + * + * @param object The object the OFValue should contain without retaining it + * @return A new, autoreleased OFValue + */ ++ (instancetype)valueWithNonretainedObject: (id)object; + /*! * @brief Initializes an already allocated OFValue with the specified bytes of * the specified type. * * @param bytes The bytes containing the value @@ -50,10 +86,33 @@ * @return An initialized OFValue */ - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType; +/*! + * @brief Initializes an already allocated OFValue containing the specified + * pointer. + * + * Only the raw value of the pointer is stored and no data will be copied. + * + * @param pointer The pointer the OFValue should contain + * @return An initialized OFValue + */ +- (instancetype)initWithPointer: (const void *)pointer; + +/*! + * @brief Initializes an already allocated OFValue containing the specified + * non-retained object. + * + * The object is not retained, which makes this useful for storing objects in + * collections without retaining them. + * + * @param object The object the OFValue should contain without retaining it + * @return An initialized OFValue + */ +- (instancetype)initWithNonretainedObject: (id)object; + /*! * @brief Gets the value. * * If the specified size does not match, this raises an * @ref OFOutOfRangeException. Index: src/OFValue.m ================================================================== --- src/OFValue.m +++ src/OFValue.m @@ -15,12 +15,15 @@ * file. */ #import "OFValue.h" #import "OFValue_bytes.h" +#import "OFValue_nonretainedObject.h" +#import "OFValue_pointer.h" #import "OFMethodSignature.h" +#import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" static struct { Class isa; } placeholder; @@ -33,10 +36,21 @@ objCType: (const char *)objCType { return (id)[[OFValue_bytes alloc] initWithBytes: bytes objCType: objCType]; } + +- (instancetype)initWithPointer: (const void *)pointer +{ + return (id)[[OFValue_pointer alloc] initWithPointer: pointer]; +} + +- (instancetype)initWithNonretainedObject: (id)object +{ + return (id)[[OFValue_nonretainedObject alloc] + initWithNonretainedObject: object]; +} @end @implementation OFValue + (void)initialize { @@ -56,14 +70,34 @@ objCType: (const char *)objCType { return [[[self alloc] initWithBytes: bytes objCType: objCType] autorelease]; } + ++ (instancetype)valueWithPointer: (const void *)pointer +{ + return [[[self alloc] initWithPointer: pointer] autorelease]; +} + ++ (instancetype)valueWithNonretainedObject: (id)object +{ + return [[[self alloc] initWithNonretainedObject: object] autorelease]; +} - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType { + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithPointer: (const void *)pointer +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithNonretainedObject: (id)object +{ OF_INVALID_INIT_METHOD } - (bool)isEqual: (id)object { @@ -139,6 +173,26 @@ - (void)getValue: (void *)value size: (size_t)size { OF_UNRECOGNIZED_SELECTOR } + +- (void *)pointerValue +{ + void *ret; + + [self getValue: &ret + size: sizeof(ret)]; + + return ret; +} + +- (id)nonretainedObjectValue +{ + id ret; + + [self getValue: &ret + size: sizeof(ret)]; + + return ret; +} @end Index: src/OFValue_bytes.h ================================================================== --- src/OFValue_bytes.h +++ src/OFValue_bytes.h @@ -1,8 +1,9 @@ /* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018 * Jonathan Schleifer + * 2018 + * Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/OFValue_nonretainedObject.h Index: src/OFValue_nonretainedObject.h ================================================================== --- src/OFValue_nonretainedObject.h +++ src/OFValue_nonretainedObject.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFValue.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFValue_nonretainedObject: OFValue +{ + id _object; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/OFValue_nonretainedObject.m Index: src/OFValue_nonretainedObject.m ================================================================== --- src/OFValue_nonretainedObject.m +++ src/OFValue_nonretainedObject.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFValue_nonretainedObject.h" +#import "OFMethodSignature.h" + +#import "OFOutOfRangeException.h" + +@implementation OFValue_nonretainedObject +@synthesize nonretainedObjectValue = _object; + +- (instancetype)initWithNonretainedObject: (id)object +{ + self = [super init]; + + _object = object; + + return self; +} + +- (void)getValue: (void *)value + size: (size_t)size +{ + if (size != sizeof(_object)) + @throw [OFOutOfRangeException exception]; + + memcpy(value, &_object, sizeof(_object)); +} + +- (void *)pointerValue +{ + return _object; +} +@end ADDED src/OFValue_pointer.h Index: src/OFValue_pointer.h ================================================================== --- src/OFValue_pointer.h +++ src/OFValue_pointer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFValue.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFValue_pointer: OFValue +{ + void *_pointer; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/OFValue_pointer.m Index: src/OFValue_pointer.m ================================================================== --- src/OFValue_pointer.m +++ src/OFValue_pointer.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFValue_pointer.h" +#import "OFMethodSignature.h" + +#import "OFOutOfRangeException.h" + +@implementation OFValue_pointer +@synthesize pointerValue = _pointer; + +- (instancetype)initWithPointer: (const void *)pointer +{ + self = [super init]; + + _pointer = (void *)pointer; + + return self; +} + +- (void)getValue: (void *)value + size: (size_t)size +{ + if (size != sizeof(_pointer)) + @throw [OFOutOfRangeException exception]; + + memcpy(value, &_pointer, sizeof(_pointer)); +} + +- (id)nonretainedObjectValue +{ + return _pointer; +} +@end Index: tests/OFValueTests.m ================================================================== --- tests/OFValueTests.m +++ tests/OFValueTests.m @@ -32,10 +32,11 @@ - (void)valueTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; of_range_t range = of_range(1, 64), range2 = of_range(1, 64); OFValue *value; + void *pointer = &value; TEST(@"+[valueWithBytes:objCType:]", (value = [OFValue valueWithBytes: &range objCType: @encode(of_range_t)])) @@ -50,8 +51,34 @@ EXPECT_EXCEPTION(@"-[getValue:size:] with wrong size throws", OFOutOfRangeException, [value getValue: &range size: sizeof(of_range_t) - 1]) + TEST(@"+[valueWithPointer:]", + (value = [OFValue valueWithPointer: pointer])) + + TEST(@"-[pointerValue]", + [value pointerValue] == pointer && + [[OFValue valueWithBytes: &pointer + objCType: @encode(void *)] pointerValue] == pointer) + + EXPECT_EXCEPTION(@"-[pointerValue] with wrong size throws", + OFOutOfRangeException, + [[OFValue valueWithBytes: "a" + objCType: @encode(char)] pointerValue]) + + TEST(@"+[valueWithNonretainedObject:]", + (value = [OFValue valueWithNonretainedObject: pointer])) + + TEST(@"-[nonretainedObjectValue]", + [value nonretainedObjectValue] == pointer && + [[OFValue valueWithBytes: &pointer + objCType: @encode(id)] pointerValue] == pointer) + + EXPECT_EXCEPTION(@"-[nonretainedObjectValue] with wrong size throws", + OFOutOfRangeException, + [[OFValue valueWithBytes: "a" + objCType: @encode(char)] nonretainedObjectValue]) + [pool drain]; } @end