Commit 4e913309b92138cdc6ff31fbce4e8afa2ab5458e

Carlos Martín Nieto 2011-06-17T16:38:21

Move transports to an inheritance model Rather than an 'private' pointer, make the private structures inherit from the generic git_transport struct. This way, we only have to worry about one memory allocation instead of two. The structures are so simple that this may even make the code use less memory overall. Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>

diff --git a/include/git2/pkt.h b/include/git2/pkt.h
index 59826da..0b17b3e 100644
--- a/include/git2/pkt.h
+++ b/include/git2/pkt.h
@@ -52,4 +52,5 @@ struct git_pkt_ref {
 };
 
 int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
+int git_pkt_send_flush(int s);
 void git_pkt_free(git_pkt *pkt);
diff --git a/include/git2/types.h b/include/git2/types.h
index ef80435..dae96cf 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -177,7 +177,7 @@ typedef struct git_transport git_transport;
 /** Whether to push or pull */
 typedef enum git_net_direction git_net_direction;
 
-typedef int (*git_transport_cb)(git_transport *transport);
+typedef int (*git_transport_cb)(git_transport **transport);
 
 typedef struct git_remote_head git_remote_head;
 typedef struct git_headarray git_headarray;
diff --git a/src/transport.c b/src/transport.c
index fb0dc32..59aecb4 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -17,7 +17,7 @@ struct {
 	{NULL, 0}
 };
 
-static git_transport_cb transport_fill_fn(const char *url)
+static git_transport_cb transport_new_fn(const char *url)
 {
 	int i = 0;
 
@@ -43,7 +43,7 @@ static git_transport_cb transport_fill_fn(const char *url)
  * Public API *
  **************/
 
-int git_transport_dummy(git_transport *GIT_UNUSED(transport))
+int git_transport_dummy(git_transport **GIT_UNUSED(transport))
 {
 	GIT_UNUSED_ARG(transport);
 	return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry");
@@ -55,13 +55,11 @@ int git_transport_new(git_transport **out, git_repository *repo, const char *url
 	git_transport *transport;
 	int error;
 
-	fn = transport_fill_fn(url);
+	fn = transport_new_fn(url);
 
-	transport = git__malloc(sizeof(git_transport));
-	if (transport == NULL)
-		return GIT_ENOMEM;
-
-	memset(transport, 0x0, sizeof(git_transport));
+	error = fn(&transport);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to create new transport");
 
 	transport->url = git__strdup(url);
 	if (transport->url == NULL)
@@ -69,10 +67,6 @@ int git_transport_new(git_transport **out, git_repository *repo, const char *url
 
 	transport->repo = repo;
 
-	error = fn(transport);
-	if (error < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to create new transport");
-
 	*out = transport;
 
 	return GIT_SUCCESS;
diff --git a/src/transport.h b/src/transport.h
index e951d4c..6d5f037 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -78,8 +78,8 @@ struct git_transport {
 	void (*free)(struct git_transport *transport);
 };
 
-int git_transport_local(struct git_transport *transport);
-int git_transport_git(struct git_transport *transport);
-int git_transport_dummy(struct git_transport *transport);
+int git_transport_local(struct git_transport **transport);
+int git_transport_git(struct git_transport **transport);
+int git_transport_dummy(struct git_transport **transport);
 
 #endif
diff --git a/src/transport_git.c b/src/transport_git.c
index eb5f708..ca1f044 100644
--- a/src/transport_git.c
+++ b/src/transport_git.c
@@ -45,10 +45,12 @@
 #include "netops.h"
 
 typedef struct {
+	git_transport parent;
 	int socket;
 	git_vector refs;
 	git_remote_head **heads;
-} git_priv;
+} transport_git;
+
 /*
  * Create a git procol request.
  *
@@ -141,7 +143,7 @@ static int extract_host_and_port(char **host, char **port, const char *url)
  * out. For convenience this also takes care of asking for the remote
  * refs
  */
-static int do_connect(git_priv *priv, const char *url)
+static int do_connect(transport_git *t, const char *url)
 {
 	int s = -1;
 	char *host, *port;
@@ -155,7 +157,7 @@ static int do_connect(git_priv *priv, const char *url)
 	s = gitno_connect(host, port);
 	connected = 1;
 	error = send_request(s, NULL, url);
-	priv->socket = s;
+	t->socket = s;
 
 	free(host);
 	free(port);
@@ -171,10 +173,10 @@ static int do_connect(git_priv *priv, const char *url)
 /*
  * Read from the socket and store the references in the vector
  */
-static int store_refs(git_priv *priv)
+static int store_refs(transport_git *t)
 {
-	int s = priv->socket;
-	git_vector *refs = &priv->refs;
+	int s = t->socket;
+	git_vector *refs = &t->refs;
 	int error = GIT_SUCCESS;
 	char buffer[1024];
 	const char *line_end, *ptr;
@@ -239,33 +241,26 @@ static int store_refs(git_priv *priv)
  */
 static int git_connect(git_transport *transport, git_net_direction direction)
 {
-	git_priv *priv;
+	transport_git *t = (transport_git *) transport;
 	int error = GIT_SUCCESS;
 
 	if (direction == INTENT_PUSH)
 		return git__throw(GIT_EINVALIDARGS, "Pushing is not supported with the git protocol");
 
-	priv = git__malloc(sizeof(git_priv));
-	if (priv == NULL)
-		return GIT_ENOMEM;
-
-	memset(priv, 0x0, sizeof(git_priv));
-	transport->private = priv;
-	error = git_vector_init(&priv->refs, 16, NULL);
+	error = git_vector_init(&t->refs, 16, NULL);
 	if (error < GIT_SUCCESS)
 		goto cleanup;
 
 	/* Connect and ask for the refs */
-	error = do_connect(priv, transport->url);
+	error = do_connect(t, transport->url);
 	if (error < GIT_SUCCESS)
 		return error;
 
-	error = store_refs(priv);
+	error = store_refs(t);
 
 cleanup:
 	if (error < GIT_SUCCESS) {
-		git_vector_free(&priv->refs);
-		free(priv);
+		git_vector_free(&t->refs);
 	}
 
 	return error;
@@ -273,8 +268,8 @@ cleanup:
 
 static int git_ls(git_transport *transport, git_headarray *array)
 {
-	git_priv *priv = transport->private;
-	git_vector *refs = &priv->refs;
+	transport_git *t = (transport_git *) transport;
+	git_vector *refs = &t->refs;
 	int len = 0;
 	unsigned int i;
 
@@ -291,19 +286,19 @@ static int git_ls(git_transport *transport, git_headarray *array)
 		array->heads[i] = &(((git_pkt_ref *) p)->head);
 	}
 	array->len = len;
-	priv->heads = array->heads;
+	t->heads = array->heads;
 
 	return GIT_SUCCESS;
 }
 
 static int git_close(git_transport *transport)
 {
-	git_priv *priv = transport->private;
-	int s = priv->socket;
+	transport_git *t = (transport_git*) transport;
+	int s = t->socket;
 	int error;
 
-	/* FIXME:  We probably want to send a flush pkt back */
-
+	/* Can't do anything if there's an error, so don't bother checking  */
+	git_pkt_send_flush(s);
 	error = close(s);
 	if (error < 0)
 		error = git__throw(GIT_EOSERR, "Failed to close socket");
@@ -313,8 +308,8 @@ static int git_close(git_transport *transport)
 
 static void git_free(git_transport *transport)
 {
-	git_priv *priv = transport->private;
-	git_vector *refs = &priv->refs;
+	transport_git *t = (transport_git *) transport;
+	git_vector *refs = &t->refs;
 	unsigned int i;
 
 	for (i = 0; i < refs->length; ++i) {
@@ -323,18 +318,25 @@ static void git_free(git_transport *transport)
 	}
 
 	git_vector_free(refs);
-	free(priv->heads);
-	free(priv);
-	free(transport->url);
-	free(transport);
+	free(t->heads);
+	free(t->parent.url);
+	free(t);
 }
 
-int git_transport_git(git_transport *transport)
+int git_transport_git(git_transport **out)
 {
-	transport->connect = git_connect;
-	transport->ls = git_ls;
-	transport->close = git_close;
-	transport->free = git_free;
+	transport_git *t;
+
+	t = git__malloc(sizeof(transport_git));
+	if (t == NULL)
+		return GIT_ENOMEM;
+
+	t->parent.connect = git_connect;
+	t->parent.ls = git_ls;
+	t->parent.close = git_close;
+	t->parent.free = git_free;
+
+	*out = (git_transport *) t;
 
 	return GIT_SUCCESS;
 }
diff --git a/src/transport_local.c b/src/transport_local.c
index a096e48..5dc5c26 100644
--- a/src/transport_local.c
+++ b/src/transport_local.c
@@ -9,9 +9,10 @@
 #include "transport.h"
 
 typedef struct {
+	git_transport parent;
 	git_repository *repo;
 	git_vector *refs;
-} local_priv;
+} transport_local;
 
 static int cmp_refs(const void *a, const void *b)
 {
@@ -29,7 +30,7 @@ static int local_connect(git_transport *transport, git_net_direction GIT_UNUSED(
 {
 	git_repository *repo;
 	int error;
-	local_priv *priv;
+	transport_local *t = (transport_local *) transport;
 	const char *path;
 	const char file_prefix[] = "file://";
 	GIT_UNUSED_ARG(dir);
@@ -44,17 +45,8 @@ static int local_connect(git_transport *transport, git_net_direction GIT_UNUSED(
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to open remote");
 
-	priv = git__malloc(sizeof(local_priv));
-	if (priv == NULL) {
-		git_repository_free(repo);
-		return GIT_ENOMEM;
-	}
-
-	priv->repo = repo;
-
-	transport->private = priv;
-
-	transport->connected = 1;
+	t->repo = repo;
+	t->parent.connected = 1;
 
 	return GIT_SUCCESS;
 }
@@ -135,11 +127,11 @@ static int local_ls(git_transport *transport, git_headarray *array)
 	git_repository *repo;
 	git_vector *vec;
 	git_strarray refs;
-	local_priv *priv = transport->private;
+	transport_local *t = (transport_local *) transport;
 
 	assert(transport && transport->connected);
 
-	repo = priv->repo;
+	repo = t->repo;
 
 	error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
 	if (error < GIT_SUCCESS)
@@ -172,7 +164,7 @@ static int local_ls(git_transport *transport, git_headarray *array)
 	array->len = vec->length;
 	array->heads = (git_remote_head **)vec->contents;
 
-	priv->refs = vec;
+	t->refs = vec;
 
  out:
 
@@ -191,8 +183,8 @@ static int local_close(git_transport *GIT_UNUSED(transport))
 static void local_free(git_transport *transport)
 {
 	unsigned int i;
-	local_priv *priv = transport->private;
-	git_vector *vec = priv->refs;
+	transport_local *t = (transport_local *) transport;
+	git_vector *vec = t->refs;
 
 	assert(transport);
 
@@ -203,22 +195,29 @@ static void local_free(git_transport *transport)
 	}
 	git_vector_free(vec);
 	free(vec);
-	git_repository_free(priv->repo);
-	free(priv);
-	free(transport->url);
-	free(transport);
+	git_repository_free(t->repo);
+	free(t->parent.url);
+	free(t);
 }
 
 /**************
  * Public API *
  **************/
 
-int git_transport_local(git_transport *transport)
+int git_transport_local(git_transport **out)
 {
-	transport->connect = local_connect;
-	transport->ls = local_ls;
-	transport->close = local_close;
-	transport->free = local_free;
+	transport_local *t;
+
+	t = git__malloc(sizeof(transport_local));
+	if (t == NULL)
+		return GIT_ENOMEM;
+
+	t->parent.connect = local_connect;
+	t->parent.ls = local_ls;
+	t->parent.close = local_close;
+	t->parent.free = local_free;
+
+	*out = (git_transport *) t;
 
 	return GIT_SUCCESS;
 }