Merge pull request #52 from sergi/remove-the-stack-implementation

Remove the own stack implementation
diff --git a/diffmatchpatch/dmp.go b/diffmatchpatch/dmp.go
index f42a537..4e61821 100644
--- a/diffmatchpatch/dmp.go
+++ b/diffmatchpatch/dmp.go
@@ -849,7 +849,12 @@
 // semantically trivial equalities.
 func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
 	changes := false
-	equalities := new(Stack) // Stack of indices where equalities are found.
+	// Stack of indices where equalities are found.
+	type equality struct {
+		data int
+		next *equality
+	}
+	var equalities *equality
 
 	var lastequality string
 	// Always equal to diffs[equalities[equalitiesLength - 1]][1]
@@ -861,7 +866,10 @@
 
 	for pointer < len(diffs) {
 		if diffs[pointer].Type == DiffEqual { // Equality found.
-			equalities.Push(pointer)
+			equalities = &equality{
+				data: pointer,
+				next: equalities,
+			}
 			lengthInsertions1 = lengthInsertions2
 			lengthDeletions1 = lengthDeletions2
 			lengthInsertions2 = 0
@@ -881,7 +889,7 @@
 				(len(lastequality) <= difference1) &&
 				(len(lastequality) <= difference2) {
 				// Duplicate record.
-				insPoint := equalities.Peek().(int)
+				insPoint := equalities.data
 				diffs = append(
 					diffs[:insPoint],
 					append([]Diff{Diff{DiffDelete, lastequality}}, diffs[insPoint:]...)...)
@@ -889,11 +897,13 @@
 				// Change second copy to insert.
 				diffs[insPoint+1].Type = DiffInsert
 				// Throw away the equality we just deleted.
-				equalities.Pop()
+				equalities = equalities.next
 
-				if equalities.Len() > 0 {
-					equalities.Pop()
-					pointer = equalities.Peek().(int)
+				if equalities != nil {
+					equalities = equalities.next
+				}
+				if equalities != nil {
+					pointer = equalities.data
 				} else {
 					pointer = -1
 				}
@@ -1106,7 +1116,11 @@
 func (dmp *DiffMatchPatch) DiffCleanupEfficiency(diffs []Diff) []Diff {
 	changes := false
 	// Stack of indices where equalities are found.
-	equalities := new(Stack)
+	type equality struct {
+		data int
+		next *equality
+	}
+	var equalities *equality
 	// Always equal to equalities[equalitiesLength-1][1]
 	lastequality := ""
 	pointer := 0 // Index of current position.
@@ -1123,13 +1137,16 @@
 			if len(diffs[pointer].Text) < dmp.DiffEditCost &&
 				(postIns || postDel) {
 				// Candidate found.
-				equalities.Push(pointer)
+				equalities = &equality{
+					data: pointer,
+					next: equalities,
+				}
 				preIns = postIns
 				preDel = postDel
 				lastequality = diffs[pointer].Text
 			} else {
 				// Not a candidate, and can never become one.
-				equalities.Clear()
+				equalities = nil
 				lastequality = ""
 			}
 			postIns = false
@@ -1165,24 +1182,29 @@
 				((preIns && preDel && postIns && postDel) ||
 					((len(lastequality) < dmp.DiffEditCost/2) && sumPres == 3)) {
 
+				insPoint := equalities.data
+
 				// Duplicate record.
-				diffs = append(diffs[:equalities.Peek().(int)],
-					append([]Diff{Diff{DiffDelete, lastequality}}, diffs[equalities.Peek().(int):]...)...)
+				diffs = append(diffs[:insPoint],
+					append([]Diff{Diff{DiffDelete, lastequality}}, diffs[insPoint:]...)...)
 
 				// Change second copy to insert.
-				diffs[equalities.Peek().(int)+1].Type = DiffInsert
-				equalities.Pop() // Throw away the equality we just deleted.
+				diffs[insPoint+1].Type = DiffInsert
+				// Throw away the equality we just deleted.
+				equalities = equalities.next
 				lastequality = ""
 
 				if preIns && preDel {
 					// No changes made which could affect previous entry, keep going.
 					postIns = true
 					postDel = true
-					equalities.Clear()
+					equalities = nil
 				} else {
-					if equalities.Len() > 0 {
-						equalities.Pop()
-						pointer = equalities.Peek().(int)
+					if equalities != nil {
+						equalities = equalities.next
+					}
+					if equalities != nil {
+						pointer = equalities.data
 					} else {
 						pointer = -1
 					}
diff --git a/diffmatchpatch/dmp_test.go b/diffmatchpatch/dmp_test.go
index a543085..99883bc 100644
--- a/diffmatchpatch/dmp_test.go
+++ b/diffmatchpatch/dmp_test.go
@@ -1562,6 +1562,21 @@
 	}
 }
 
+func Benchmark_DiffCleanupSemantic(b *testing.B) {
+	s1 := readFile("speedtest1.txt", b)
+	s2 := readFile("speedtest2.txt", b)
+
+	dmp := New()
+
+	diffs := dmp.DiffMain(s1, s2, false)
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		dmp.DiffCleanupSemantic(diffs)
+	}
+}
+
 func readFile(filename string, b *testing.B) string {
 	bytes, err := ioutil.ReadFile(filename)
 	if err != nil {
diff --git a/diffmatchpatch/stack.go b/diffmatchpatch/stack.go
deleted file mode 100644
index 045f5d3..0000000
--- a/diffmatchpatch/stack.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package diffmatchpatch
-
-import (
-	"fmt"
-)
-
-// Stack represents a generic stack implementation.
-type Stack struct {
-	top  *Element
-	size int
-}
-
-// Element holds a generic stack element.
-type Element struct {
-	value interface{}
-	next  *Element
-}
-
-// Len returns the stack's length
-func (s *Stack) Len() int {
-	return s.size
-}
-
-// Push appends a new element onto the stack
-func (s *Stack) Push(value interface{}) {
-	s.top = &Element{value, s.top}
-	s.size++
-}
-
-// Pop removes the top element from the stack and return its value
-// If the stack is empty, return nil
-func (s *Stack) Pop() (value interface{}) {
-	if s.size > 0 {
-		value, s.top = s.top.value, s.top.next
-		s.size--
-		return
-	}
-	return nil
-}
-
-// Peek returns the value of the element on the top of the stack
-// but don't remove it. If the stack is empty, return nil
-func (s *Stack) Peek() (value interface{}) {
-	if s.size > 0 {
-		value = s.top.value
-		return
-	}
-	return -1
-}
-
-// Clear empties the stack
-func (s *Stack) Clear() {
-	s.top = nil
-	s.size = 0
-}
-
-func main() {
-	stack := new(Stack)
-
-	stack.Push("Things")
-	stack.Push("and")
-	stack.Push("Stuff")
-
-	for stack.Len() > 0 {
-		fmt.Printf("%s ", stack.Pop().(string))
-	}
-	fmt.Println()
-}