<commit_before>package vcfgo

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/brentp/irelate/interfaces"
)

// Variant holds the information about a single site. It is analagous to a row in a VCF file.
type Variant struct {
	Chromosome string
	Pos        uint64
	Id_        string
	Reference  string
	Alternate  []string
	Quality    float32
	Filter     string
	Info_      interfaces.Info
	Format     []string
	Samples    []*SampleGenotype
	// if lazy parsing, then just save the sample strings here.
	sampleString string
	Header       *Header
	LineNumber   int64
}

func (v *Variant) Info() interfaces.Info {
	return v.Info_
}

func (v *Variant) Id() string {
	return v.Id_
}

func (v *Variant) Ref() string {
	return v.Reference
}

func (v *Variant) Alt() []string {
	return v.Alternate
}

// Chrom returns the chromosome name.
func (v *Variant) Chrom() string {
	return v.Chromosome
}

// Start returns the 0-based start
func (v *Variant) Start() uint32 {
	return uint32(v.Pos - 1)
}

// CIPos reports the Left and Right end of an SV using the CIPOS tag. It is in
// bed format so the end is +1'ed. E.g. If there is not CIPOS, the return value
// is v.Start(), v.Start() + 1
func (v *Variant) CIPos() (uint32, uint32, bool) {
	if v.Header == nil {
		v.Header = NewHeader()
	}
	if _, ok := v.Header.Infos["CIPOS"]; !ok {
		v.Header.Infos["CIPOS"] = &Info{Id: "CIPOS", Number: "2", Description: "CIPOS", Type: "Integer"}
	}
	s := v.Start()
	ipair, err := v.Info().Get("CIPOS")
	if ipair == nil && err != nil {
		return s, s + 1, false
	}
	pair, ok := ipair.([]int)
	if !ok {
		return s, s + 1, false
	}
	left := pair[0]
	right := pair[1]
	return uint32(int(s) + left), uint32(int(s) + right + 1), true
}

// CIEnd reports the Left and Right end of an SV using the CIEND tag. It is in
// bed format so the end is +1'ed. E.g. If there is no CIEND, the return value
// is v.End() - 1, v.End()
func (v *Variant) CIEnd() (uint32, uint32, bool) {
	if v.Header == nil {
		v.Header = NewHeader()
	}
	if _, ok := v.Header.Infos["CIEND"]; !ok {
		v.Header.Lock()
		v.Header.Infos["CIEND"] = &Info{Id: "CIEND", Number: "2", Description: "CIEND", Type: "Integer"}
		v.Header.Unlock()
	}
	e := v.End()
	ipair, err := v.Info().Get("CIEND")
	if ipair == nil && err != nil {
		return e - 1, e, false
	}
	pair, ok := ipair.([]int)
	if !ok {
		return e - 1, e, false
	}
	left := pair[0]
	right := pair[1]
	return uint32(int(e)+left) - 1, uint32(int(e) + right), true<commit_msg>fix race condition with CIPos/CIEnd<commit_after>package vcfgo

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/brentp/irelate/interfaces"
)

// Variant holds the information about a single site. It is analagous to a row in a VCF file.
type Variant struct {
	Chromosome string
	Pos        uint64
	Id_        string
	Reference  string
	Alternate  []string
	Quality    float32
	Filter     string
	Info_      interfaces.Info
	Format     []string
	Samples    []*SampleGenotype
	// if lazy parsing, then just save the sample strings here.
	sampleString string
	Header       *Header
	LineNumber   int64
}

func (v *Variant) Info() interfaces.Info {
	return v.Info_
}

func (v *Variant) Id() string {
	return v.Id_
}

func (v *Variant) Ref() string {
	return v.Reference
}

func (v *Variant) Alt() []string {
	return v.Alternate
}

// Chrom returns the chromosome name.
func (v *Variant) Chrom() string {
	return v.Chromosome
}

// Start returns the 0-based start
func (v *Variant) Start() uint32 {
	return uint32(v.Pos - 1)
}

// CIPos reports the Left and Right end of an SV using the CIPOS tag. It is in
// bed format so the end is +1'ed. E.g. If there is not CIPOS, the return value
// is v.Start(), v.Start() + 1
func (v *Variant) CIPos() (uint32, uint32, bool) {
	if v.Header == nil {
		v.Header = NewHeader()
	}
	s := v.Start()
	v.Header.RLock()
	if _, ok := v.Header.Infos["CIPOS"]; !ok {
		v.Header.RUnlock()
		v.Header.Lock()
		v.Header.Infos["CIPOS"] = &Info{Id: "CIPOS", Number: "2", Description: "CIPOS", Type: "Integer"}
		v.Header.Unlock()
		v.Header.RLock()
	}
	ipair, err := v.Info().Get("CIPOS")
	v.Header.RUnlock()
	if ipair == nil && err != nil {
		return s, s + 1, false
	}
	pair, ok := ipair.([]int)
	if !ok {
		return s, s + 1, false
	}
	left := pair[0]
	right := pair[1]
	return uint32(int(s) + left), uint32(int(s) + right + 1), true
}

// CIEnd reports the Left and Right end of an SV using the CIEND tag. It is in
// bed format so the end is +1'ed. E.g. If there is no CIEND, the return value
// is v.End() - 1, v.End()
func (v *Variant) CIEnd() (uint32, uint32, bool) {
	if v.Header == nil {
		v.Header = NewHeader()
	}
	e := v.End()
	v.Header.RLock()
	if _, ok := v.Header.Infos["CIEND"]; !ok {
		v.Header.RUnlock()
		v.Header.Lock()
		v.Header.Infos["CIEND"] = &Info{Id: "CIEND", Number: "2", Description: "CIEND", Type: "Integer"}
		v.Header.Unlock()
		v.Header.RLock()
	}
	ipair, err := v.Info().Get("CIEND")
	v.Header.RUnlock()
	if ipair == nil && err != nil {
		return e - 1, e, false
	}
	pair, ok := ipair.([]int)
	if !ok {
		return e - 1, e, false
	}
	left := pair[0]
	right := pair[1]
	return uint32(int(e)+left) - 1, uint32(int(e) + right), true
{'fraction_non_alphanumeric': 0.1581691772885284, 'fraction_numerical': 0.016994978756276556, 'mean_word_length': 3.1103174603174604, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2696064', 'n_tokens_mistral': 2096, 'n_tokens_neox': 1989, 'n_words': 645}