Skip to content

Instantly share code, notes, and snippets.

@MrSaints
Created July 14, 2017 21:32
Show Gist options
  • Save MrSaints/6f7b7b5ea24ccfbe0fc88211237a170e to your computer and use it in GitHub Desktop.
Save MrSaints/6f7b7b5ea24ccfbe0fc88211237a170e to your computer and use it in GitHub Desktop.
A radix trie inspired structure with priority queues.
package converter
import (
"container/heap"
"mime"
"strings"
)
type ConverterPriorityQueueItem struct {
converter Converter
priority int
index int
}
type ConverterPriorityQueue []*ConverterPriorityQueueItem
func (pq ConverterPriorityQueue) Len() int { return len(pq) }
func (pq ConverterPriorityQueue) Less(i, j int) bool {
return pq[i].priority > pq[j].priority
}
func (pq ConverterPriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *ConverterPriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*ConverterPriorityQueueItem)
item.index = n
*pq = append(*pq, item)
}
func (pq *ConverterPriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.index = -1
*pq = old[0 : n-1]
return item
}
type ConverterTree struct {
root *ConverterTreeNode
}
type ConverterTreeNode struct {
mimeType string
nodes []*ConverterTreeNode
converters ConverterPriorityQueue
}
func (parentNode *ConverterTreeNode) GetNode(mimeType string) *ConverterTreeNode {
for _, node := range parentNode.nodes {
if strings.HasPrefix(mimeType, node.mimeType) {
return node
}
}
return nil
}
func (t *ConverterTree) Add(c Converter, mimeType string, priority int) error {
if t.root == nil {
t.root = &ConverterTreeNode{}
}
currentNode := t.root
currentMimeType := mimeType
for {
if currentMimeType == "" {
if currentNode.converters == nil {
pq := make(ConverterPriorityQueue, 1)
heap.Init(&pq)
}
heap.Push(&currentNode.converters, &ConverterPriorityQueueItem{
converter: c,
priority: priority,
})
return nil
}
targetNode := currentNode.GetNode(currentMimeType)
if targetNode != nil {
currentNode = targetNode
currentMimeType = strings.Trim(currentMimeType[len(targetNode.mimeType):], "/")
continue
}
mt, _, err := mime.ParseMediaType(currentMimeType)
if err != nil {
return err
}
parts := strings.SplitN(mt, "/", 2)
if len(parts) > 0 {
newNode := &ConverterTreeNode{
mimeType: parts[0],
}
currentNode.nodes = append(currentNode.nodes, newNode)
currentNode = newNode
if len(parts) == 2 {
currentMimeType = parts[1]
continue
}
}
currentMimeType = ""
}
return nil
}
@MrSaints
Copy link
Author

The "I don't know why I did this, but I thought I needed it" moment ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment