Browse Source

Handle exact duplicate Col ranges

Geoffrey J. Teale 6 years ago
parent
commit
a7f296edfd
2 changed files with 101 additions and 67 deletions
  1. 74 52
      col.go
  2. 27 15
      col_test.go

+ 74 - 52
col.go

@@ -146,99 +146,121 @@ type colStoreNode struct {
 	Next *colStoreNode
 	Next *colStoreNode
 }
 }
 
 
+// ColStore is the working store of Col definitions, it will simplify all Cols added to it, to ensure there ar no overlapping definitions.
+type ColStore struct {
+	Root *colStoreNode
+}
+
+// Add a Col to the ColStore. If it overwrites all, or part of some
+// existing Col's range of columns the that Col will be adjusted
+// and/or split to make room for the new Col.
+func (cs *ColStore) Add(col *Col) {
+	newNode := &colStoreNode{Col: col}
+	if cs.Root == nil {
+		cs.Root = newNode
+		return
+	}
+	cs.makeWay(cs.Root, newNode)
+	return
+}
+
 // makeWay will adjust the Min and Max of this colStoreNode's Col to
 // makeWay will adjust the Min and Max of this colStoreNode's Col to
 // make way for a new colStoreNode's Col. If necessary it will
 // make way for a new colStoreNode's Col. If necessary it will
 // generate an additional colStoreNode with a new Col covering the
 // generate an additional colStoreNode with a new Col covering the
 // "tail" portion of this colStoreNode's Col should the new node lay
 // "tail" portion of this colStoreNode's Col should the new node lay
 // completely within the range of this one, but without reaching its
 // completely within the range of this one, but without reaching its
 // maximum extent.
 // maximum extent.
-func (csn *colStoreNode) makeWay(node *colStoreNode) {
+func (cs *ColStore) makeWay(node1, node2 *colStoreNode) {
 	switch {
 	switch {
-	case csn.Col.Max < node.Col.Min:
-		// The new node starts after this one ends, there's no overlap
+	case node1.Col.Max < node2.Col.Min:
+		// The new node2 starts after this one ends, there's no overlap
 		//
 		//
 		// Node1 |----|
 		// Node1 |----|
 		// Node2        |----|
 		// Node2        |----|
-		if csn.Next != nil {
-			csn.Next.makeWay(node)
+		if node1.Next != nil {
+			cs.makeWay(node1.Next, node2)
 			return
 			return
 		}
 		}
-		csn.Next = node
-		node.Prev = csn
+		node1.Next = node2
+		node2.Prev = node1
 		return
 		return
 
 
-	case csn.Col.Min > node.Col.Max:
-		// The new node ends before this one begins, there's no overlap
+	case node1.Col.Min > node2.Col.Max:
+		// The new node2 ends before this one begins, there's no overlap
 		//
 		//
 		// Node1         |-----|
 		// Node1         |-----|
 		// Node2  |----|
 		// Node2  |----|
-		if csn.Prev != nil {
-			csn.Prev.makeWay(node)
+		if node1.Prev != nil {
+			cs.makeWay(node1.Prev, node2)
 			return
 			return
 		}
 		}
-		csn.Prev = node
-		node.Next = csn
+		node1.Prev = node2
+		node2.Next = node1
 		return
 		return
 
 
-	case csn.Col.Min < node.Col.Min && csn.Col.Max > node.Col.Max:
-		// The new node bisects this one:
+	case node1.Col.Min == node2.Col.Min && node1.Col.Max == node2.Col.Max:
+		// Exact match
+		//
+		// Node1 |xxx|
+		// Node2 |---|
+		if node1.Prev != nil {
+			node1.Prev.Next = node2
+			node2.Prev = node1.Prev
+			node1.Prev = nil
+		}
+		if node1.Next != nil {
+			node1.Next.Prev = node2
+			node2.Next = node1.Next
+			node1.Next = nil
+		}
+		if cs.Root == node1 {
+			cs.Root = node2
+		}
+
+	case node1.Col.Min < node2.Col.Min && node1.Col.Max > node2.Col.Max:
+		// The new node2 bisects this one:
 		//
 		//
 		// Node1 |---xx---|
 		// Node1 |---xx---|
 		// Node2    |--|
 		// Node2    |--|
-		newCol := csn.Col.copyToRange(node.Col.Max+1, csn.Col.Max)
-		newNode := &colStoreNode{Col: newCol, Prev: node, Next: csn.Next}
-		csn.Col.Max = node.Col.Min - 1
-		csn.Next = node
-		node.Prev = csn
-		node.Next = newNode
+		newCol := node1.Col.copyToRange(node2.Col.Max+1, node1.Col.Max)
+		newNode := &colStoreNode{Col: newCol, Prev: node2, Next: node1.Next}
+		node1.Col.Max = node2.Col.Min - 1
+		node1.Next = node2
+		node2.Prev = node1
+		node2.Next = newNode
 		return
 		return
 
 
-	case csn.Col.Max >= node.Col.Min && csn.Col.Min < node.Col.Min:
-		// The new node overlaps this one at some point above it's minimum:
+	case node1.Col.Max >= node2.Col.Min && node1.Col.Min < node2.Col.Min:
+		// The new node2 overlaps this one at some point above it's minimum:
 		//
 		//
 		//  Node1  |----xx|
 		//  Node1  |----xx|
 		//  Node2      |-------|
 		//  Node2      |-------|
-		csn.Col.Max = node.Col.Min - 1
-		if csn.Next != nil {
+		node1.Col.Max = node2.Col.Min - 1
+		if node1.Next != nil {
 			// Break the link to this node, which prevents
 			// Break the link to this node, which prevents
 			// us looping back and forth forever
 			// us looping back and forth forever
-			csn.Next.Prev = nil
-			csn.Next.makeWay(node)
+			node1.Next.Prev = nil
+			cs.makeWay(node1.Next, node2)
 		}
 		}
-		csn.Next = node
-		node.Prev = csn
+		node1.Next = node2
+		node2.Prev = node1
 		return
 		return
 
 
-	case csn.Col.Min <= node.Col.Max && csn.Col.Min > node.Col.Min:
-		// The new node overlaps this one at some point below it's maximum:
+	case node1.Col.Min <= node2.Col.Max && node1.Col.Min > node2.Col.Min:
+		// The new node2 overlaps this one at some point below it's maximum:
 		//
 		//
 		// Node1:     |------|
 		// Node1:     |------|
 		// Node2: |----xx|
 		// Node2: |----xx|
-		csn.Col.Min = node.Col.Max + 1
-		if csn.Prev != nil {
+		node1.Col.Min = node2.Col.Max + 1
+		if node1.Prev != nil {
 			// Break the link to this node, which prevents
 			// Break the link to this node, which prevents
 			// us looping back and forth forever
 			// us looping back and forth forever
-			csn.Prev.Next = nil
-			csn.Prev.makeWay(node)
+			node1.Prev.Next = nil
+			cs.makeWay(node1.Prev, node2)
 		}
 		}
-		csn.Prev = node
-		node.Next = csn
-		return
-	}
-	return
-}
-
-type ColStore struct {
-	Root *colStoreNode
-}
-
-//
-func (cs *ColStore) Add(col *Col) {
-	newNode := &colStoreNode{Col: col}
-	if cs.Root == nil {
-		cs.Root = newNode
+		node1.Prev = node2
+		node2.Next = node1
 		return
 		return
 	}
 	}
-	cs.Root.makeWay(newNode)
 	return
 	return
 }
 }

+ 27 - 15
col_test.go

@@ -143,23 +143,35 @@ func (css *ColStoreSuite) TestMakeWay(c *C) {
 			c.Assert(node3.Col.Max, Equals, 7)
 			c.Assert(node3.Col.Max, Equals, 7)
 		})
 		})
 
 
-	// Col1: |--|
-	// Col2:          |--|
-	// Col3:     |
-	assertWayMade([]*Col{&Col{Min: 0, Max: 7}, &Col{Min: 3, Max: 4}},
+	// Col1: |xx|
+	// Col2: |--|
+	assertWayMade([]*Col{&Col{Min: 0, Max: 1, Width: 40.1}, &Col{Min: 0, Max: 1, Width: 10.0}},
 		func(root *colStoreNode) {
 		func(root *colStoreNode) {
 			c.Assert(root.Prev, IsNil)
 			c.Assert(root.Prev, IsNil)
-			c.Assert(root.Next, NotNil)
-			node2 := root.Next
-			c.Assert(node2.Prev, Equals, root)
-			c.Assert(node2.Col.Min, Equals, 3)
-			c.Assert(node2.Col.Max, Equals, 4)
-			c.Assert(node2.Next, NotNil)
-			node3 := node2.Next
-			c.Assert(node3.Prev, Equals, node2)
-			c.Assert(node3.Next, IsNil)
-			c.Assert(node3.Col.Min, Equals, 5)
-			c.Assert(node3.Col.Max, Equals, 7)
+			c.Assert(root.Next, IsNil)
+			c.Assert(root.Col.Min, Equals, 0)
+			c.Assert(root.Col.Max, Equals, 1)
+			// This is how we establish we have the new node, and not the old one
+			c.Assert(root.Col.Width, Equals, 10.0)
 		})
 		})
 
 
+	// Col1: |--|
+	// Col2:          |--|
+	// Col3:     |
+	// assertWayMade([]*Col{&Col{Min: 0, Max: 7}, &Col{Min: 3, Max: 4}},
+	// 	func(root *colStoreNode) {
+	// 		c.Assert(root.Prev, IsNil)
+	// 		c.Assert(root.Next, NotNil)
+	// 		node2 := root.Next
+	// 		c.Assert(node2.Prev, Equals, root)
+	// 		c.Assert(node2.Col.Min, Equals, 3)
+	// 		c.Assert(node2.Col.Max, Equals, 4)
+	// 		c.Assert(node2.Next, NotNil)
+	// 		node3 := node2.Next
+	// 		c.Assert(node3.Prev, Equals, node2)
+	// 		c.Assert(node3.Next, IsNil)
+	// 		c.Assert(node3.Col.Min, Equals, 5)
+	// 		c.Assert(node3.Col.Max, Equals, 7)
+	// 	})
+
 }
 }