changeset 571:e4ee4bf4c7d0

Let session context control creation of Path instances
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 11 Apr 2013 16:27:06 +0200
parents 36853bb80a35
children becd2a1310a2
files src/org/tmatesoft/hg/core/HgCloneCommand.java src/org/tmatesoft/hg/core/HgLogCommand.java src/org/tmatesoft/hg/core/HgRepoFacade.java src/org/tmatesoft/hg/core/SessionContext.java src/org/tmatesoft/hg/internal/SubrepoManager.java src/org/tmatesoft/hg/repo/HgDataFile.java src/org/tmatesoft/hg/repo/HgManifest.java src/org/tmatesoft/hg/repo/HgRepository.java
diffstat 8 files changed, 48 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCloneCommand.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java	Thu Apr 11 16:27:06 2013 +0200
@@ -146,6 +146,7 @@
 		private final ProgressSupport progressSupport;
 		private final CancelSupport cancelSupport;
 		private final SessionContext ctx;
+		private final Path.Source pathFactory;
 		private FileOutputStream indexFile;
 		private String filename; // human-readable name of the file being written, for log/exception purposes 
 
@@ -174,6 +175,7 @@
 			progressSupport = progress;
 			cancelSupport = cancel;
 			revlogDataZip = new RevlogCompressor(sessionCtx);
+			pathFactory = ctx.getPathFactory();
 		}
 
 		public void initEmptyRepository() throws IOException {
@@ -243,7 +245,7 @@
 			try {
 				revlogHeader.offset(0).baseRevision(-1);
 				revisionSequence.clear();
-				fncacheFile.add(Path.create(name)); 
+				fncacheFile.add(pathFactory.path(name)); 
 				File file = new File(hgDir, filename = storagePathHelper.rewrite(name).toString());
 				file.getParentFile().mkdirs();
 				indexFile = new FileOutputStream(file);
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/core/HgLogCommand.java	Thu Apr 11 16:27:06 2013 +0200
@@ -230,7 +230,8 @@
 	 * @return <code>this</code> for convenience
 	 */
 	public HgLogCommand file(String file, boolean followCopyRename) {
-		return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename);
+		Path.Source ps = repo.getSessionContext().getPathFactory();
+		return file(ps.path(repo.getToRepoPathHelper().rewrite(file)), followCopyRename);
 	}
 
 	/**
@@ -238,7 +239,8 @@
 	 * @return <code>this</code> for convenience
 	 */
 	public HgLogCommand file(String file, boolean followCopyRename, boolean followFileAncestry) {
-		return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename, followFileAncestry);
+		Path.Source ps = repo.getSessionContext().getPathFactory();
+		return file(ps.path(repo.getToRepoPathHelper().rewrite(file)), followCopyRename, followFileAncestry);
 	}
 	
 	/**
--- a/src/org/tmatesoft/hg/core/HgRepoFacade.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/core/HgRepoFacade.java	Thu Apr 11 16:27:06 2013 +0200
@@ -36,7 +36,7 @@
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
-public class HgRepoFacade {
+public class HgRepoFacade implements SessionContext.Source {
 	private HgRepository repo;
 	private final SessionContext context;
 
@@ -97,6 +97,10 @@
 		}
 		return repo;
 	}
+	
+	public SessionContext getSessionContext() {
+		return context;
+	}
 
 	public HgLogCommand createLogCommand() {
 		return new HgLogCommand(repo/*, getCommandContext()*/);
--- a/src/org/tmatesoft/hg/core/SessionContext.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/core/SessionContext.java	Thu Apr 11 16:27:06 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
 package org.tmatesoft.hg.core;
 
 import org.tmatesoft.hg.util.LogFacility;
+import org.tmatesoft.hg.util.Path;
 
 /**
  * Access to objects that might need to be shared between various distinct operations ran during the same working session 
@@ -47,6 +48,25 @@
 	// e.g. when there's standalone Caches and WritableSessionProperties objects
 
 	/**
+	 * Provide a factory to create {@link Path} objects.
+	 * 
+	 * Occasionally, there's a need to construct a {@link Path} object from a string/byte data 
+	 * kept in mercurial control files. Generally, default implementation (with {@link Path#create(CharSequence)} 
+	 * is enough, however, if there's a need to control number of string objects in memory (i.e. prevent duplicates),
+	 * default implementation might need to be replaced with more sophisticated (e.g. using weak references or
+	 * just a huge hash set).
+	 * 
+	 * @return factory to construct Path objects, never <code>null</code>
+	 */
+	public Path.Source getPathFactory() {
+		return new Path.Source() {
+			public Path path(CharSequence p) {
+				return Path.create(p);
+			}
+		};
+	}
+
+	/**
 	 * Providers of the context may implement
 	 */
 	public interface Source {
--- a/src/org/tmatesoft/hg/internal/SubrepoManager.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/SubrepoManager.java	Thu Apr 11 16:27:06 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -81,6 +81,7 @@
 			String line;
 			LinkedList<HgSubrepoLocation> res = new LinkedList<HgSubrepoLocation>();
 			HgInternals hgRepoInternal = new HgInternals(repo);
+			final Path.Source pathFactory = repo.getSessionContext().getPathFactory();
 			while ((line = br.readLine()) != null) {
 				int sep = line.indexOf('=');
 				if (sep == -1) {
@@ -109,7 +110,7 @@
 				//
 				// apparently, key value can't end with '/', `hg commit` fails if it does:
 				// abort: path ends in directory separator: fourth/
-				Path p = Path.create(key.charAt(key.length()-1) == '/' ? key : key + '/');
+				Path p = pathFactory.path(key.charAt(key.length()-1) == '/' ? key : key + '/');
 				String revValue = substate.get(key);
 				HgSubrepoLocation loc = hgRepoInternal.newSubrepo(p, value, kind, revValue == null ? null : Nodeid.fromAscii(revValue));
 				res.add(loc);
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Thu Apr 11 16:27:06 2013 +0200
@@ -401,7 +401,8 @@
 	 */
 	public Path getCopySourceName() throws HgRuntimeException {
 		if (isCopy()) {
-			return Path.create(metadata.find(0, "copy"));
+			Path.Source ps = getRepo().getSessionContext().getPathFactory();
+			return ps.path(metadata.find(0, "copy"));
 		}
 		throw new UnsupportedOperationException(); // XXX REVISIT, think over if Exception is good (clients would check isCopy() anyway, perhaps null is sufficient?)
 	}
--- a/src/org/tmatesoft/hg/repo/HgManifest.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgManifest.java	Thu Apr 11 16:27:06 2013 +0200
@@ -194,7 +194,7 @@
 			manifestLast = manifestFirst;
 			manifestFirst = x;
 		}
-		content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector, encodingHelper));
+		content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector));
 	}
 	
 	/**
@@ -214,7 +214,7 @@
 			throw new IllegalArgumentException();
 		}
 		int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector);
-		content.iterate(manifestRevs, true, new ManifestParser(inspector, encodingHelper));
+		content.iterate(manifestRevs, true, new ManifestParser(inspector));
 	}
 	
 	// 
@@ -399,18 +399,16 @@
 	 * of the String, but these are only for unique Strings (Paths) (3020 in the example above). Besides, I save
 	 * useless char[] and byte->char conversions. 
 	 */
-	private static class PathProxy {
+	private final class PathProxy {
 		private byte[] data;
 		private int start; 
 		private final int hash, length;
 		private Path result;
-		private final EncodingHelper encHelper;
 
-		public PathProxy(byte[] data, int start, int length, EncodingHelper eh) {
+		public PathProxy(byte[] data, int start, int length) {
 			this.data = data;
 			this.start = start;
 			this.length = length;
-			this.encHelper = eh;
 
 			// copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode
 			// just need some nice algorithm here
@@ -448,7 +446,8 @@
 		
 		public Path freeze() {
 			if (result == null) {
-				result = Path.create(encHelper.fromManifest(data, start, length));
+				Path.Source pathFactory = HgManifest.this.getRepo().getSessionContext().getPathFactory();
+				result = pathFactory.path(HgManifest.this.encodingHelper.fromManifest(data, start, length));
 				// release reference to bigger data array, make a copy of relevant part only
 				// use original bytes, not those from String above to avoid cache misses due to different encodings 
 				byte[] d = new byte[length];
@@ -460,19 +459,17 @@
 		}
 	}
 
-	private static class ManifestParser implements RevlogStream.Inspector, Lifecycle {
+	private class ManifestParser implements RevlogStream.Inspector, Lifecycle {
 		private final Inspector inspector;
 		private IdentityPool<Nodeid> nodeidPool, thisRevPool;
 		private final IdentityPool<PathProxy> fnamePool;
 		private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool
 		private final ProgressSupport progressHelper;
 		private IterateControlMediator iterateControl;
-		private final EncodingHelper encHelper;
 		
-		public ManifestParser(Inspector delegate, EncodingHelper eh) {
+		public ManifestParser(Inspector delegate) {
 			assert delegate != null;
 			inspector = delegate;
-			encHelper = eh;
 			nodeidPool = new IdentityPool<Nodeid>();
 			fnamePool = new IdentityPool<PathProxy>();
 			thisRevPool = new IdentityPool<Nodeid>();
@@ -496,7 +493,7 @@
 						int x = i;
 						for( ; data[i] != '\n' && i < actualLen; i++) {
 							if (fname == null && data[i] == 0) {
-								PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x, encHelper));
+								PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x));
 								// if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit
 								// cpython 0..10k: hits: 15 989 152, misses: 3020
 								fname = px.freeze();
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Apr 11 16:07:17 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Apr 11 16:27:06 2013 +0200
@@ -266,7 +266,7 @@
 	
 	public HgDataFile getFileNode(String path) {
 		CharSequence nPath = normalizePath.rewrite(path);
-		Path p = Path.create(nPath);
+		Path p = sessionContext.getPathFactory().path(nPath);
 		return getFileNode(p);
 	}