Implemented OOWeakSet - like NSMutableSet, but uses weakrefs and cleans them up as needed.
Use OOWeakSet for _shipsOnHold in StationEntity. This implementation is pretty naive. I have a "better" version, only it consistently crashes a lot. Also, integrated unit tests (when building with Xcode 4). Tests are run at the end of TestRelease and Deployment builds, and can be run manually with Product -> Test. git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@5109 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
parent
3e6098fa3c
commit
5cafda59d9
@ -667,6 +667,8 @@
|
||||
1AED2D0C0C04586C004A1118 /* OOGraphicsResetManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AED2D0A0C04586C004A1118 /* OOGraphicsResetManager.h */; };
|
||||
1AED2D0D0C04586C004A1118 /* OOGraphicsResetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AED2D0B0C04586C004A1118 /* OOGraphicsResetManager.m */; };
|
||||
1AEF57D312E51DDB00546444 /* OOJSEngineNativeWrappers.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AEF57D212E51DDB00546444 /* OOJSEngineNativeWrappers.h */; };
|
||||
1AF4AF4A15B858AA009243BE /* OOWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AF4AF4815B858AA009243BE /* OOWeakSet.h */; };
|
||||
1AF4AF4B15B858AA009243BE /* OOWeakSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AF4AF4915B858AA009243BE /* OOWeakSet.m */; };
|
||||
2512833E09BA27C100F43D55 /* Octree.m in Sources */ = {isa = PBXBuildFile; fileRef = 2512833C09BA27C100F43D55 /* Octree.m */; settings = {COMPILER_FLAGS = $OO_MATHS_OPTS; }; };
|
||||
2512833F09BA27C100F43D55 /* Octree.h in Headers */ = {isa = PBXBuildFile; fileRef = 2512833D09BA27C100F43D55 /* Octree.h */; };
|
||||
2512834209BA27EC00F43D55 /* Geometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 2512834009BA27EC00F43D55 /* Geometry.h */; };
|
||||
@ -800,6 +802,13 @@
|
||||
remoteGlobalIDString = 8D5B49B6048680CD000E48DA;
|
||||
remoteInfo = DebugOXP;
|
||||
};
|
||||
1AB2D62315B86EA500177AAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 1AB2D61C15B86EA400177AAF /* OoliteUnitTests.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 1A0CD53615AF0BCE00970505;
|
||||
remoteInfo = OoliteUnitTests;
|
||||
};
|
||||
1AB7760112CA2E53001478BB /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 1AB775FC12CA2E53001478BB /* libjs.xcodeproj */;
|
||||
@ -1854,6 +1863,7 @@
|
||||
1AB2AAF80C4CE0CC0008CF4E /* OOOXPVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOOXPVerifier.h; sourceTree = "<group>"; };
|
||||
1AB2AAF90C4CE0CC0008CF4E /* OOOXPVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOOXPVerifier.m; sourceTree = "<group>"; };
|
||||
1AB2AB120C4CE4070008CF4E /* verifyOXP.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; name = verifyOXP.plist; path = ../../../Resources/Config/verifyOXP.plist; sourceTree = "<group>"; };
|
||||
1AB2D61C15B86EA400177AAF /* OoliteUnitTests.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OoliteUnitTests.xcodeproj; path = tests/OCUnitTests/OoliteUnitTests.xcodeproj; sourceTree = "<group>"; };
|
||||
1AB4AEB60D688AD9003076D6 /* OOLogHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOLogHeader.h; sourceTree = "<group>"; };
|
||||
1AB4AEB70D688AD9003076D6 /* OOLogHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOLogHeader.m; sourceTree = "<group>"; };
|
||||
1AB5E1ED12BD628500C334DD /* OOJoystickManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOJoystickManager.h; sourceTree = "<group>"; };
|
||||
@ -1946,6 +1956,8 @@
|
||||
1AED2D0A0C04586C004A1118 /* OOGraphicsResetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOGraphicsResetManager.h; sourceTree = "<group>"; };
|
||||
1AED2D0B0C04586C004A1118 /* OOGraphicsResetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOGraphicsResetManager.m; sourceTree = "<group>"; };
|
||||
1AEF57D212E51DDB00546444 /* OOJSEngineNativeWrappers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOJSEngineNativeWrappers.h; sourceTree = "<group>"; };
|
||||
1AF4AF4815B858AA009243BE /* OOWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOWeakSet.h; sourceTree = "<group>"; };
|
||||
1AF4AF4915B858AA009243BE /* OOWeakSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOWeakSet.m; sourceTree = "<group>"; };
|
||||
1AF8E33A0CC169F500CA6001 /* contributors.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = contributors.txt; sourceTree = "<group>"; };
|
||||
2512833C09BA27C100F43D55 /* Octree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Octree.m; sourceTree = "<group>"; };
|
||||
2512833D09BA27C100F43D55 /* Octree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Octree.h; sourceTree = "<group>"; };
|
||||
@ -2909,6 +2921,8 @@
|
||||
1AEB4919119D5AAA007BD514 /* OORegExpMatcher.m */,
|
||||
1A062C8711B28D8A00727C1D /* NSObjectOOExtensions.h */,
|
||||
1A062C8811B28D8A00727C1D /* NSObjectOOExtensions.m */,
|
||||
1AF4AF4815B858AA009243BE /* OOWeakSet.h */,
|
||||
1AF4AF4915B858AA009243BE /* OOWeakSet.m */,
|
||||
);
|
||||
name = Utilities;
|
||||
sourceTree = "<group>";
|
||||
@ -3135,6 +3149,14 @@
|
||||
path = OXPVerifier;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB2D61D15B86EA400177AAF /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1AB2D62415B86EA500177AAF /* OoliteUnitTests.octest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB775FD12CA2E53001478BB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -3219,6 +3241,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AF4AF4C15B8616F009243BE /* Unit tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1AB2D61C15B86EA400177AAF /* OoliteUnitTests.xcodeproj */,
|
||||
);
|
||||
name = "Unit tests";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97314FDCFA39411CA2CEA /* Oolite_GUSTO */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -3230,6 +3260,7 @@
|
||||
1A5BF2710916D45B00BF238F /* External bundles */,
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||
1AF4AF4C15B8616F009243BE /* Unit tests */,
|
||||
1AEA229D12CBD18600EC0F43 /* CoreServices.framework */,
|
||||
1A033F90132687DC006F9DB7 /* Quartz.framework */,
|
||||
);
|
||||
@ -3479,6 +3510,7 @@
|
||||
1A6F665314DF323900695C11 /* OODefaultShaderSynthesizer.h in Headers */,
|
||||
1ABA415E15ACBB6700F7E841 /* DockEntity.h in Headers */,
|
||||
1ABA416215ADAB8D00F7E841 /* OOJSDock.h in Headers */,
|
||||
1AF4AF4A15B858AA009243BE /* OOWeakSet.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -3569,6 +3601,10 @@
|
||||
ProductGroup = 1A3E018F11C574AC000FF226 /* Products */;
|
||||
ProjectRef = 1A3E018E11C574AC000FF226 /* Oolite-importer.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 1AB2D61D15B86EA400177AAF /* Products */;
|
||||
ProjectRef = 1AB2D61C15B86EA400177AAF /* OoliteUnitTests.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 1AE3455212CB77AC00FD8C62 /* Products */;
|
||||
ProjectRef = 1AE3455112CB77AC00FD8C62 /* Vorbis.xcodeproj */;
|
||||
@ -3625,6 +3661,13 @@
|
||||
remoteRef = 1A8FAA9D12F0E44D008FF5A2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
1AB2D62415B86EA500177AAF /* OoliteUnitTests.octest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = OoliteUnitTests.octest;
|
||||
remoteRef = 1AB2D62315B86EA500177AAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
1AB7760212CA2E53001478BB /* libjs_for_oolite.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@ -3933,6 +3976,7 @@
|
||||
1A6F665414DF323900695C11 /* OODefaultShaderSynthesizer.m in Sources */,
|
||||
1ABA415F15ACBB6700F7E841 /* DockEntity.m in Sources */,
|
||||
1ABA416315ADAB8D00F7E841 /* OOJSDock.m in Sources */,
|
||||
1AF4AF4B15B858AA009243BE /* OOWeakSet.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -4071,6 +4115,7 @@
|
||||
);
|
||||
PRODUCT_NAME = Oolite;
|
||||
SECTORDER_FLAGS = "";
|
||||
TEST_AFTER_BUILD = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "\"$(DEPS_INCLUDE_PATH)/ogg\" \"$(DEPS_INCLUDE_PATH)/js\" \"$(DEPS_INCLUDE_PATH)/vorbis\" \"$(DEPS_INCLUDE_PATH)/png\" \"$(SRCROOT)/src/Core/\" \"$(SRCROOT)/src/Core/Tables/\" \"$(SRCROOT)/src/Core/Entites/\" \"$(SRCROOT)/src/Core/Materials/\" \"$(SRCROOT)/src/BSDCompat/\"";
|
||||
WARNING_CFLAGS = (
|
||||
"-Wall",
|
||||
@ -4137,6 +4182,7 @@
|
||||
);
|
||||
PRODUCT_NAME = Oolite;
|
||||
SECTORDER_FLAGS = "";
|
||||
TEST_AFTER_BUILD = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "\"$(DEPS_INCLUDE_PATH)/ogg\" \"$(DEPS_INCLUDE_PATH)/js\" \"$(DEPS_INCLUDE_PATH)/vorbis\" \"$(DEPS_INCLUDE_PATH)/png\" \"$(SRCROOT)/src/Core/\" \"$(SRCROOT)/src/Core/Tables/\" \"$(SRCROOT)/src/Core/Entites/\" \"$(SRCROOT)/src/Core/Materials/\" \"$(SRCROOT)/src/BSDCompat/\"";
|
||||
WARNING_CFLAGS = (
|
||||
"-Wall",
|
||||
|
@ -42,6 +42,16 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1A0CD53515AF0BCE00970505"
|
||||
BuildableName = "OoliteUnitTests.octest"
|
||||
BlueprintName = "OoliteUnitTests"
|
||||
ReferencedContainer = "container:tests/OCUnitTests/OoliteUnitTests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
@ -34,6 +34,20 @@
|
||||
ReferencedContainer = "container:Oolite.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1A0CD53515AF0BCE00970505"
|
||||
BuildableName = "OoliteUnitTests.octest"
|
||||
BlueprintName = "OoliteUnitTests"
|
||||
ReferencedContainer = "container:tests/OCUnitTests/OoliteUnitTests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
@ -42,6 +56,16 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Deployment">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1A0CD53515AF0BCE00970505"
|
||||
BuildableName = "OoliteUnitTests.octest"
|
||||
BlueprintName = "OoliteUnitTests"
|
||||
ReferencedContainer = "container:tests/OCUnitTests/OoliteUnitTests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@ -55,7 +79,7 @@
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Deployment"
|
||||
|
@ -21,7 +21,7 @@
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "NO"
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
@ -34,6 +34,20 @@
|
||||
ReferencedContainer = "container:Oolite.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1A0CD53515AF0BCE00970505"
|
||||
BuildableName = "OoliteUnitTests.octest"
|
||||
BlueprintName = "OoliteUnitTests"
|
||||
ReferencedContainer = "container:tests/OCUnitTests/OoliteUnitTests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
@ -42,6 +56,16 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "TestRelease">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1A0CD53515AF0BCE00970505"
|
||||
BuildableName = "OoliteUnitTests.octest"
|
||||
BlueprintName = "OoliteUnitTests"
|
||||
ReferencedContainer = "container:tests/OCUnitTests/OoliteUnitTests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
@ -26,7 +26,9 @@ MA 02110-1301, USA.
|
||||
|
||||
#import "ShipEntity.h"
|
||||
#import "Universe.h"
|
||||
#import "legacy_random.h"
|
||||
|
||||
@class OOWeakSet;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -45,10 +47,11 @@ typedef enum
|
||||
|
||||
#define DOCKING_CLEARANCE_WINDOW 126.0
|
||||
|
||||
|
||||
@interface StationEntity: ShipEntity
|
||||
{
|
||||
@private
|
||||
NSMutableSet *_shipsOnHold;
|
||||
OOWeakSet *_shipsOnHold;
|
||||
DockEntity *player_reserved_dock;
|
||||
double last_launch_time;
|
||||
double approach_spacing;
|
||||
|
@ -44,6 +44,7 @@ MA 02110-1301, USA.
|
||||
#import "OOJSScript.h"
|
||||
#import "OODebugGLDrawing.h"
|
||||
#import "OODebugFlags.h"
|
||||
#import "OOWeakSet.h"
|
||||
|
||||
|
||||
@interface StationEntity (OOPrivate)
|
||||
@ -57,8 +58,6 @@ MA 02110-1301, USA.
|
||||
|
||||
- (NSDictionary *) holdPositionInstructionForShip:(ShipEntity *)ship;
|
||||
|
||||
- (void) compactShipsOnHold;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -244,28 +243,11 @@ MA 02110-1301, USA.
|
||||
// if all docks have no ships on approach
|
||||
[shipAI message:@"DOCKING_COMPLETE"];
|
||||
}
|
||||
|
||||
[self compactShipsOnHold];
|
||||
}
|
||||
|
||||
|
||||
- (void) compactShipsOnHold
|
||||
{
|
||||
NSArray *ships = [_shipsOnHold allObjects];
|
||||
OOUInteger i, count = [ships count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
OOWeakReference *ref = [ships objectAtIndex:i];
|
||||
if ([ref weakRefUnderlyingObject] == nil)
|
||||
{
|
||||
[_shipsOnHold removeObject:ref];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// only used by player - everything else ends up in a Dock's launch queue
|
||||
- (void) launchShip:(ShipEntity*)ship
|
||||
- (void) launchShip:(ShipEntity *)ship
|
||||
{
|
||||
NSEnumerator *subEnum = nil;
|
||||
DockEntity* sub = nil;
|
||||
@ -303,17 +285,13 @@ MA 02110-1301, USA.
|
||||
- (void) abortAllDockings
|
||||
{
|
||||
NSEnumerator *subEnum = nil;
|
||||
DockEntity* sub = nil;
|
||||
DockEntity *sub = nil;
|
||||
for (subEnum = [self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
|
||||
{
|
||||
[sub abortAllDockings];
|
||||
}
|
||||
|
||||
OOWeakReference *ref = nil;
|
||||
foreach (ref, _shipsOnHold)
|
||||
{
|
||||
[[ref weakRefUnderlyingObject] sendAIMessage:@"DOCKING_ABORTED"];
|
||||
}
|
||||
[_shipsOnHold makeObjectsPerformSelector:@selector(sendAIMessage:) withObject:@"DOCKING_ABORTED"];
|
||||
[_shipsOnHold removeAllObjects];
|
||||
|
||||
[shipAI message:@"DOCKING_COMPLETE"];
|
||||
@ -323,14 +301,11 @@ MA 02110-1301, USA.
|
||||
|
||||
- (void) autoDockShipsOnHold
|
||||
{
|
||||
OOWeakReference *ref = nil;
|
||||
foreach (ref, _shipsOnHold)
|
||||
NSEnumerator *onHoldEnum = [_shipsOnHold objectEnumerator];
|
||||
ShipEntity *ship = nil;
|
||||
while ((ship = [onHoldEnum nextObject]))
|
||||
{
|
||||
ShipEntity *ship = [ref weakRefUnderlyingObject];
|
||||
if (ship != nil)
|
||||
{
|
||||
[self pullInShipIfPermitted:ship];
|
||||
}
|
||||
[self pullInShipIfPermitted:ship];
|
||||
}
|
||||
|
||||
[_shipsOnHold removeAllObjects];
|
||||
@ -488,9 +463,7 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
|
||||
}
|
||||
|
||||
// we made it through holding!
|
||||
OOWeakReference *weakShip = [ship weakRetain];
|
||||
[_shipsOnHold removeObject:weakShip];
|
||||
[weakShip release];
|
||||
[_shipsOnHold removeObject:ship];
|
||||
|
||||
[shipAI reactToMessage:@"DOCKING_REQUESTED" context:@"requestDockingCoordinates"]; // react to the request
|
||||
|
||||
@ -498,15 +471,13 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary *) holdPositionInstructionForShip:(ShipEntity *)ship
|
||||
- (NSDictionary *)holdPositionInstructionForShip:(ShipEntity *)ship
|
||||
{
|
||||
OOWeakReference *weakShip = [ship weakRetain];
|
||||
if (![_shipsOnHold containsObject:weakShip])
|
||||
if (![_shipsOnHold containsObject:ship])
|
||||
{
|
||||
[self sendExpandedMessage:@"[station-acknowledges-hold-position]" toShip:ship];
|
||||
[_shipsOnHold addObject:weakShip];
|
||||
[_shipsOnHold addObject:ship];
|
||||
}
|
||||
[weakShip release];
|
||||
|
||||
return OOMakeDockingInstructions(self, [ship position], 0, 100, @"HOLD_POSITION", nil, NO);
|
||||
}
|
||||
@ -516,9 +487,7 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
|
||||
{
|
||||
[ship sendAIMessage:@"DOCKING_ABORTED"];
|
||||
|
||||
OOWeakReference *weakShip = [ship weakRetain];
|
||||
[_shipsOnHold removeObject:weakShip];
|
||||
[weakShip release];
|
||||
[_shipsOnHold removeObject:ship];
|
||||
|
||||
NSEnumerator *subEnum = nil;
|
||||
DockEntity *sub = nil;
|
||||
@ -546,7 +515,7 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
|
||||
if (self != nil)
|
||||
{
|
||||
isStation = YES;
|
||||
_shipsOnHold = [[NSMutableSet alloc] init];
|
||||
_shipsOnHold = [[OOWeakSet alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
@ -2296,17 +2265,17 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
|
||||
} */
|
||||
|
||||
// Ships on hold list, only used with moving stations (= carriers)
|
||||
[self compactShipsOnHold];
|
||||
if([_shipsOnHold count] > 0)
|
||||
{
|
||||
OOLog(@"dumpState.stationEntity", @"%i Ships on hold (unsorted):", [_shipsOnHold count]);
|
||||
OOWeakReference *ref = nil;
|
||||
|
||||
OOLogIndent();
|
||||
unsigned i = 1;
|
||||
foreach (ref, _shipsOnHold)
|
||||
NSEnumerator *onHoldEnum = [_shipsOnHold objectEnumerator];
|
||||
ShipEntity *ship = nil;
|
||||
unsigned i = 1;
|
||||
while ((ship = [onHoldEnum nextObject]))
|
||||
{
|
||||
ShipEntity *ship = [ref weakRefUnderlyingObject];
|
||||
OOLog(@"dumpState.stationEntity", @"Nr %i: %@ at distance %g with role: %@", i++, [ship displayName], distance(position, [ship position]), [ship primaryRole]);
|
||||
OOLog(@"dumpState.stationEntity", @"Nr %i: %@ at distance %g with role: %@", i++, [ship displayName], distance([self position], [ship position]), [ship primaryRole]);
|
||||
}
|
||||
OOLogOutdent();
|
||||
}
|
||||
|
54
src/Core/OOWeakSet.h
Normal file
54
src/Core/OOWeakSet.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
OOWeakSet.h
|
||||
|
||||
A mutable set of weak references to objects conforming to OOWeakReferenceSupport.
|
||||
|
||||
Semantics:
|
||||
* When an object in the set is deallocated, the object is removed from the
|
||||
set and the set's count drops. There is no notification for this. As such,
|
||||
there is no such thing as an immutable weak set.
|
||||
* Objects are uniqued by pointer equality, not isEquals:.
|
||||
* OOWeakSet is not thread-safe. It not only requires that all operations on
|
||||
it happen on one thread, but also that objects it's watching are (finally)
|
||||
released on that thread.
|
||||
|
||||
|
||||
LIMITATION: fast enumeration and Oolite's foreach() macro are not supported.
|
||||
|
||||
|
||||
Written by Jens Ayton in 2012 for Oolite.
|
||||
This code is hereby placed in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOWeakReference.h"
|
||||
|
||||
|
||||
@interface OOWeakSet: NSObject <NSCopying, NSMutableCopying>
|
||||
{
|
||||
@private
|
||||
NSMutableSet *_objects;
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
- (id) initWithCapacity:(NSUInteger)capacity; // As with Foundation collections, capacity is only a hint.
|
||||
|
||||
+ (id) set;
|
||||
+ (id) setWithCapacity:(NSUInteger)capacity;
|
||||
|
||||
- (NSUInteger) count;
|
||||
- (BOOL) containsObject:(id<OOWeakReferenceSupport>)object;
|
||||
- (NSEnumerator *) objectEnumerator;
|
||||
|
||||
- (void) addObject:(id<OOWeakReferenceSupport>)object; // Unlike NSSet, adding nil fails silently.
|
||||
- (void) removeObject:(id<OOWeakReferenceSupport>)object; // Like NSSet, does not complain if object is not already a member.
|
||||
|
||||
- (void) addObjectsByEnumerating:(NSEnumerator *)enumerator;
|
||||
|
||||
- (void) makeObjectsPerformSelector:(SEL)selector;
|
||||
- (void) makeObjectsPerformSelector:(SEL)selector withObject:(id)argument;
|
||||
|
||||
- (void) removeAllObjects;
|
||||
|
||||
@end
|
298
src/Core/OOWeakSet.m
Normal file
298
src/Core/OOWeakSet.m
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
|
||||
OOWeakSet.h
|
||||
|
||||
Written by Jens Ayton in 2012 for Oolite.
|
||||
This code is hereby placed in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOWeakSet.h"
|
||||
#import "OOCocoa.h"
|
||||
|
||||
|
||||
@interface OOWeakRefUnpackingEnumerator: NSEnumerator
|
||||
{
|
||||
@private
|
||||
NSEnumerator *_enumerator;
|
||||
}
|
||||
|
||||
- (id) initWithEnumerator:(NSEnumerator *)enumerator;
|
||||
|
||||
+ (id) enumeratorWithCollection:(id)collection; // Collection must implement -objectEnumerator
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface OOWeakSet (OOPrivate)
|
||||
|
||||
- (void) compact; // Remove any zeroed entries.
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOWeakSet
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithCapacity:0];
|
||||
}
|
||||
|
||||
|
||||
- (id) initWithCapacity:(OOUInteger)capacity
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_objects = [[NSMutableSet alloc] initWithCapacity:capacity];
|
||||
if (_objects == NULL)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+ (id) set
|
||||
{
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
|
||||
+ (id) setWithCapacity:(OOUInteger)capacity
|
||||
{
|
||||
return [[[self alloc] initWithCapacity:capacity] autorelease];
|
||||
}
|
||||
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
DESTROY(_objects);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p>{", [self class], self];
|
||||
NSEnumerator *selfEnum = [self objectEnumerator];
|
||||
id object = nil;
|
||||
BOOL first = YES;
|
||||
while ((object = [selfEnum nextObject]))
|
||||
{
|
||||
if (!first) [result appendString:@", "];
|
||||
else first = NO;
|
||||
|
||||
NSString *desc = nil;
|
||||
if ([object respondsToSelector:@selector(shortDescription)]) desc = [object shortDescription];
|
||||
else desc = [object description];
|
||||
|
||||
[result appendString:desc];
|
||||
}
|
||||
|
||||
[result appendString:@"}"];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// MARK: Protocol conformance
|
||||
|
||||
- (id) copyWithZone:(NSZone *)zone
|
||||
{
|
||||
[self compact];
|
||||
OOWeakSet *result = [[OOWeakSet allocWithZone:zone] init];
|
||||
[result addObjectsByEnumerating:[self objectEnumerator]];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (id) mutableCopyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [self copyWithZone:zone];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isEqual:(id)other
|
||||
{
|
||||
if (![other isKindOfClass:[OOWeakSet class]]) return NO;
|
||||
if ([self count] != [other count]) return NO;
|
||||
|
||||
BOOL result = YES;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSEnumerator *selfEnum = [self objectEnumerator];
|
||||
id object = nil;
|
||||
while ((object = [selfEnum nextObject]))
|
||||
{
|
||||
if (![other containsObject:object])
|
||||
{
|
||||
result = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DESTROY(pool);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// MARK: Meat and potatoes
|
||||
|
||||
- (OOUInteger) count
|
||||
{
|
||||
[self compact];
|
||||
return [_objects count];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) containsObject:(id<OOWeakReferenceSupport>)object
|
||||
{
|
||||
[self compact];
|
||||
OOWeakReference *weakObj = [object weakRetain];
|
||||
BOOL result = [_objects containsObject:weakObj];
|
||||
[weakObj release];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (NSEnumerator *) objectEnumerator
|
||||
{
|
||||
return [OOWeakRefUnpackingEnumerator enumeratorWithCollection:_objects];
|
||||
}
|
||||
|
||||
|
||||
- (void) addObject:(id<OOWeakReferenceSupport>)object
|
||||
{
|
||||
if (object == nil) return;
|
||||
NSAssert([object conformsToProtocol:@protocol(OOWeakReferenceSupport)], @"Attempt to add object to OOWeakSet which does not conform to OOWeakReferenceSupport.");
|
||||
|
||||
OOWeakReference *weakObj = [object weakRetain];
|
||||
[_objects addObject:weakObj];
|
||||
[weakObj release];
|
||||
}
|
||||
|
||||
|
||||
- (void) removeObject:(id<OOWeakReferenceSupport>)object
|
||||
{
|
||||
OOWeakReference *weakObj = [object weakRetain];
|
||||
[_objects removeObject:weakObj];
|
||||
[weakObj release];
|
||||
}
|
||||
|
||||
|
||||
- (void) addObjectsByEnumerating:(NSEnumerator *)enumerator
|
||||
{
|
||||
id object = nil;
|
||||
[self compact];
|
||||
while ((object = [enumerator nextObject]))
|
||||
{
|
||||
[self addObject:object];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) makeObjectsPerformSelector:(SEL)selector
|
||||
{
|
||||
OOWeakReference *weakRef = nil;
|
||||
foreach (weakRef, _objects)
|
||||
{
|
||||
[[weakRef weakRefUnderlyingObject] performSelector:selector];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) makeObjectsPerformSelector:(SEL)selector withObject:(id)argument
|
||||
{
|
||||
OOWeakReference *weakRef = nil;
|
||||
foreach (weakRef, _objects)
|
||||
{
|
||||
[[weakRef weakRefUnderlyingObject] performSelector:selector withObject:argument];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
[_objects removeAllObjects];
|
||||
}
|
||||
|
||||
|
||||
- (void) compact
|
||||
{
|
||||
OOWeakReference *weakRef = nil;
|
||||
BOOL compactRequired = NO;
|
||||
foreach (weakRef, _objects)
|
||||
{
|
||||
if ([weakRef weakRefUnderlyingObject] == nil)
|
||||
{
|
||||
compactRequired = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (compactRequired)
|
||||
{
|
||||
NSMutableSet *newObjects = [[NSMutableSet alloc] initWithCapacity:[_objects count]];
|
||||
foreach (weakRef, _objects)
|
||||
{
|
||||
if ([weakRef weakRefUnderlyingObject] != nil)
|
||||
{
|
||||
[newObjects addObject:weakRef];
|
||||
}
|
||||
}
|
||||
|
||||
[_objects release];
|
||||
_objects = newObjects;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOWeakRefUnpackingEnumerator
|
||||
|
||||
- (id) initWithEnumerator:(NSEnumerator *)enumerator
|
||||
{
|
||||
if (enumerator == nil)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_enumerator = [enumerator retain];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+ (id) enumeratorWithCollection:(id)collection
|
||||
{
|
||||
return [[[self alloc] initWithEnumerator:[collection objectEnumerator]] autorelease];
|
||||
}
|
||||
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_enumerator release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
- (id) nextObject
|
||||
{
|
||||
id next = nil;
|
||||
while ((next = [_enumerator nextObject]))
|
||||
{
|
||||
next = [next weakRefUnderlyingObject];
|
||||
if (next != nil) return next;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
Loading…
x
Reference in New Issue
Block a user