Author: rfm
Date: Sat Apr 26 11:26:59 2014
New Revision: 37812

URL: http://svn.gna.org/viewcvs/gnustep?rev=37812&view=rev
Log:
add GSUniqued

Added:
    libs/performance/trunk/GSUniqued.h
    libs/performance/trunk/GSUniqued.m
Modified:
    libs/performance/trunk/ChangeLog
    libs/performance/trunk/GNUmakefile
    libs/performance/trunk/Performance.h

Modified: libs/performance/trunk/ChangeLog
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/ChangeLog?rev=37812&r1=37811&r2=37812&view=diff
==============================================================================
--- libs/performance/trunk/ChangeLog    (original)
+++ libs/performance/trunk/ChangeLog    Sat Apr 26 11:26:59 2014
@@ -1,3 +1,12 @@
+2014-04-26 Richard Frith-Macdonald  <[email protected]>
+
+       * GSUniqued.h:
+       * GSUniqued.m:
+       * Performance.h:
+       * GNUmakefile:
+       New code to implement uniqued copies of objects for lowered memory
+       footprint and faster collection lookups.
+
 2013-11-05 Niels Grewe <[email protected]>
 
        * GSFIFO.m: Fix calculation of the timeout for cooperating

Modified: libs/performance/trunk/GNUmakefile
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GNUmakefile?rev=37812&r1=37811&r2=37812&view=diff
==============================================================================
--- libs/performance/trunk/GNUmakefile  (original)
+++ libs/performance/trunk/GNUmakefile  Sat Apr 26 11:26:59 2014
@@ -43,6 +43,7 @@
        GSTicker.m \
        GSIndexedSkipList.m \
        GSSkipMutableArray.m \
+       GSUniqued.m \
 
 
 Performance_HEADER_FILES += \
@@ -54,6 +55,7 @@
        GSThroughput.h \
        GSTicker.h \
        GSSkipMutableArray.h \
+       GSUniqued.h \
 
 
 Performance_AGSDOC_FILES += \
@@ -64,7 +66,8 @@
        GSThreadPool.h \
        GSThroughput.h \
        GSTicker.h \
-       GSSkipMutableArray.h
+       GSSkipMutableArray.h \
+       GSUniqued.h \
 
 
 # Optional Java wrappers for the library

Added: libs/performance/trunk/GSUniqued.h
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSUniqued.h?rev=37812&view=auto
==============================================================================
--- libs/performance/trunk/GSUniqued.h  (added)
+++ libs/performance/trunk/GSUniqued.h  Sat Apr 26 11:26:59 2014
@@ -0,0 +1,80 @@
+#if    !defined(INCLUDED_GSUNIQUED)
+#define        INCLUDED_GSUNIQUED      1
+/**
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   Written by:  Richard Frith-Macdonald <[email protected]>
+   Date:        April 2014
+
+   This file is part of the Performance Library.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+   */
+#import <Foundation/NSObject.h>
+
+/** Class used to unique other objects.<br />
+ * <p>The point of this class is to lower the memory footprint and speed
+ * up comparisons (pointer equality) in cases where an application
+ * stores multiple copies of the same object in various maps.<br />
+ * Since uniquing is performed by storing an immutable copy of the
+ * original object in a map until there are no further references
+ * to that object, it's pointless to use this uniquing unless the
+ * application would be storing at least two copies of the object.<br />
+ * Also, since this is thread-safe there is a lock management
+ * overhead wherever a uniqued object is released, so performance
+ * gains are to be expected only if the uniqued object has a
+ * relatively long lifetime and is tested for equality with other
+ * instances frequently.<br />
+ * In short, use with care; while uniquing can have a big performance
+ * advantage for some programs, this is actually quite rare.
+ * </p>
+ * <p>The internal implementation of the uniquing works by taking
+ * immutable copies of the objects to be uniqued, storing those copies
+ * in a hash table, and swizzling their class pointers to a sub-class 
+ * which will automatically remove the instance from the hash table
+ * before it is deallocated.<br />
+ * Access to the hash table is protected by locks so that uniqued
+ * objects may be used freely in multiple threads.<br />
+ * The name of the subclass used is the name of the original class
+ * with 'GSUniqued' added as a prefix.
+ * </p>
+ */
+@interface      GSUniqued : NSObject
+
+/** This method returns a copy of its argument, uniqued so that other
+ * such copies of equal objects will be the same instance.<br />
+ * The argument must respond to -copyWithZone: by returning an instance
+ * of class of immutable objects (ie where the -hash and -isEqual:
+ * methods are stable for that instance).
+ */
++ (id) copyUniqued: (id<NSObject,NSCopying>)anObject;
+
+@end
+
+/** Category for uniquing any copyable object.<br />
+ * NB.  This must only be used by classes for which -copyWithZone: 
+ * produces an instance of an immutable class.
+ */
+@interface NSObject (GSUniqued)
+
+/** This method returns a copy of the receiver uniqued so that other
+ * such copies of equal objects content will be the same instance.
+ */
+- (id) copyUniqued;
+
+@end
+
+#endif
+

Added: libs/performance/trunk/GSUniqued.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSUniqued.m?rev=37812&view=auto
==============================================================================
--- libs/performance/trunk/GSUniqued.m  (added)
+++ libs/performance/trunk/GSUniqued.m  Sat Apr 26 11:26:59 2014
@@ -0,0 +1,176 @@
+/**
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   Written by:  Richard Frith-Macdonald <[email protected]>
+   Date:        April 2014
+
+   This file is part of the Performance Library.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+   */
+
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSException.h>
+#import <Foundation/NSHashTable.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSObjCRuntime.h>
+#import <Foundation/NSSet.h>
+#import <GNUstepBase/GSObjCRuntime.h>
+#import "GSUniqued.h"
+
+
+static Class                    GSUniquedClass = Nil;
+static NSLock                   *uniquedObjectsLock;
+static IMP                      iLock;
+static IMP                      iUnlock;
+static NSHashTable              *uniquedObjects;
+static NSLock                   *classLock;
+static NSMutableDictionary      *classMap;
+
+/* Deallocate a uniqued object ... we must remove it from the uniqued
+ * objects table and then call the real -dealloc method.
+ */
+static void
+uDealloc(id self, SEL _cmd)
+{
+  Class c;
+  IMP   i;
+
+  NSHashRemove(uniquedObjects, self);
+  c = object_getClass(self);
+  c = class_getSuperclass(c);
+  i = class_getMethodImplementation(c, _cmd);
+  (*i)(self, _cmd);
+}
+
+/* Release a uniqued object ... we must obtain a lock in case the uniqued
+ * objects table has to be modified by removal of this instance on
+ * deallocation.
+ */
+static void
+uRelease(id self, SEL _cmd)
+{
+  Class c;
+  IMP   i;
+
+  c = object_getClass(self);
+  c = class_getSuperclass(c);
+  i = class_getMethodImplementation(c, _cmd);
+  (*iLock)(uniquedObjectsLock, @selector(lock));
+  (*i)(self, _cmd);
+  (*iUnlock)(uniquedObjectsLock, @selector(unlock));
+}
+
+@implementation GSUniqued
+
++ (void) initialize
+{
+  if (Nil == GSUniquedClass)
+    {
+      classLock = [NSLock new];
+      classMap = [NSMutableDictionary new];
+      uniquedObjectsLock = [NSLock new];
+      iLock = [uniquedObjectsLock methodForSelector: @selector(lock)];
+      iUnlock = [uniquedObjectsLock methodForSelector: @selector(unlock)];
+      uniquedObjects = NSCreateHashTable(
+        NSNonRetainedObjectHashCallBacks, 10000);
+      GSUniquedClass = [GSUniqued class];
+    }
+}
+
++ (id) allocWithZone: (NSZone*)z
+{
+  [NSException raise: NSInvalidArgumentException
+              format: @"Attempt to allocate instance of GSUniqued"];
+  return nil;
+}
+
++ (id) copyUniqued: (id<NSObject,NSCopying>)anObject
+{
+  NSObject      *found;
+
+  NSAssert(nil != anObject, NSInvalidArgumentException);
+  (*iLock)(uniquedObjectsLock, @selector(lock));
+  found = [(NSObject*)NSHashGet(uniquedObjects, anObject) retain];
+  (*iUnlock)(uniquedObjectsLock, @selector(unlock));
+
+  if (nil == found)
+    {
+      NSObject  *aCopy;
+      Class     c;
+      Class     u;
+
+      aCopy = [anObject copyWithZone: NSDefaultMallocZone()];
+      c = object_getClass(aCopy);
+
+      [classLock lock];
+      u = [classMap objectForKey: c];
+      if (Nil == u)
+        {
+          const char    *cn = class_getName(c);
+          char          name[strlen(cn) + 20];
+          Method        method;
+
+          sprintf(name, "GSUniqued%s", cn);
+          u = objc_allocateClassPair(c, name, 0);
+
+          method = class_getInstanceMethod([NSObject class],
+            @selector(dealloc));
+          class_addMethod(u, @selector(dealloc),
+            (IMP)uDealloc, method_getTypeEncoding(method));
+
+          method = class_getInstanceMethod([NSObject class],
+            @selector(release));
+          class_addMethod(u, @selector(release),
+            (IMP)uRelease, method_getTypeEncoding(method));
+
+          objc_registerClassPair(u);
+          [classMap setObject: u forKey: c];
+        }
+      [classLock unlock];
+
+      (*iLock)(uniquedObjectsLock, @selector(lock));
+      found = [(NSObject*)NSHashGet(uniquedObjects, anObject) retain];
+      if (nil == found)
+        {
+          found = aCopy;
+#if defined(GNUSTEP)
+          GSClassSwizzle(found, u);
+#else
+          object_setClass(found, u);
+#endif
+          NSHashInsert(uniquedObjects, found);
+        }
+      else
+        {
+          [aCopy release];      // Already uniqued by another thread
+        }
+      (*iUnlock)(uniquedObjectsLock, @selector(unlock));
+    }
+  return found;
+}
+
+@end
+
+@implementation NSObject (GSUniqued)
+
+- (id) copyUniqued
+{
+  if (Nil == GSUniquedClass) [GSUniqued class];
+  return [GSUniquedClass copyUniqued: (id<NSObject,NSCopying>)self];
+}
+
+@end
+

Modified: libs/performance/trunk/Performance.h
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/Performance.h?rev=37812&r1=37811&r2=37812&view=diff
==============================================================================
--- libs/performance/trunk/Performance.h        (original)
+++ libs/performance/trunk/Performance.h        Sat Apr 26 11:26:59 2014
@@ -32,4 +32,5 @@
 #import "GSThroughput.h"
 #import "GSTicker.h"
 #import "GSSkipMutableArray.h"
+#import "GSUniqued.h"
 


_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs

Reply via email to