func (p *Counter) Increase(v *Primitive) *Counter {
	if !p.IsNumericType() || !v.IsNumericType() {
		panic("unsupported type")
	}
	switch p.valueType {
	case IntegerCnt:
		switch v.valueType {
		case Long:
			p.value = p.value.(int) + int(v.value.(int64))
		case Double:
			p.value = p.value.(int) + int(v.value.(float64))
		default:
			p.value = p.value.(int) + v.value.(int)
		}
		if p.value.(int) > math.MaxInt32 || p.value.(int) < math.MinInt32 {
			p.value = int64(p.value.(int))
			p.valueType = LongCnt
		}
	case LongCnt:
		switch v.valueType {
		case Integer:
			p.value = p.value.(int64) + int64(v.value.(int))
		case Double:
			p.value = p.value.(int64) + int64(v.value.(float64))
		default:
			p.value = p.value.(int64) + v.value.(int64)
		}
	case DoubleCnt:
		switch v.valueType {
		case Integer:
			p.value = p.value.(float64) + float64(v.value.(int))
		case Long:
			p.value = p.value.(float64) + float64(v.value.(int64))
		default:
			p.value = p.value.(float64) + v.value.(float64)
		}
	}
	return p
}
Increase increase integer, long or double.
If the result of the operation is greater than MaxInt32 or less
than MinInt32, Counter's value type can be changed Integer to Long.
Because in golang, int can be either int32 or int64.
So we need to assert int to int32.
package json
import (
	"encoding/binary"
	"fmt"
	"math"
	"github.com/yorkie-team/yorkie/pkg/document/time"
)
type CounterType int
const (
	IntegerCnt CounterType = iota
	LongCnt
	DoubleCnt
)
func CounterValueFromBytes(counterType CounterType, value []byte) interface{} {
	switch counterType {
	case IntegerCnt:
		val := int32(binary.LittleEndian.Uint32(value))
		return int(val)
	case LongCnt:
		return int64(binary.LittleEndian.Uint64(value))
	case DoubleCnt:
		return math.Float64frombits(binary.LittleEndian.Uint64(value))
	}
	panic("unsupported type")
}
type Counter struct {
	valueType CounterType
	value     interface{}
	createdAt *time.Ticket
	movedAt   *time.Ticket
	removedAt *time.Ticket
}
func NewCounter(value interface{}, createdAt *time.Ticket) *Counter {
	switch val := value.(type) {
	case int:
		if math.MaxInt32 < val || math.MinInt32 > val {
			return &Counter{
				valueType: LongCnt,
				value:     int64(val),
				createdAt: createdAt,
			}
		}
		return &Counter{
			valueType: IntegerCnt,
			value:     val,
			createdAt: createdAt,
		}
	case int64:
		return &Counter{
			valueType: LongCnt,
			value:     val,
			createdAt: createdAt,
		}
	case float64:
		return &Counter{
			valueType: DoubleCnt,
			value:     val,
			createdAt: createdAt,
		}
	}
	panic("unsupported type")
}
func (p *Counter) Bytes() []byte {
	switch val := p.value.(type) {
	case int:
		bytes := [4]byte{}
		binary.LittleEndian.PutUint32(bytes[:], uint32(val))
		return bytes[:]
	case int64:
		bytes := [8]byte{}
		binary.LittleEndian.PutUint64(bytes[:], uint64(val))
		return bytes[:]
	case float64:
		bytes := [8]byte{}
		binary.LittleEndian.PutUint64(bytes[:], math.Float64bits(val))
		return bytes[:]
	}
	panic("unsupported type")
}
func (p *Counter) Marshal() string {
	switch p.valueType {
	case IntegerCnt:
		return fmt.Sprintf("%d", p.value)
	case LongCnt:
		return fmt.Sprintf("%d", p.value)
	case DoubleCnt:
		return fmt.Sprintf("%f", p.value)
	}
	panic("unsupported type")
}
func (p *Counter) DeepCopy() Element {
	counter := *p
	return &counter
}
func (p *Counter) CreatedAt() *time.Ticket {
	return p.createdAt
}
func (p *Counter) MovedAt() *time.Ticket {
	return p.movedAt
}
func (p *Counter) SetMovedAt(movedAt *time.Ticket) {
	p.movedAt = movedAt
}
func (p *Counter) RemovedAt() *time.Ticket {
	return p.removedAt
}
func (p *Counter) SetRemovedAt(removedAt *time.Ticket) {
	p.removedAt = removedAt
}
func (p *Counter) Remove(removedAt *time.Ticket) bool {
	if (removedAt != nil && removedAt.After(p.createdAt)) &&
		(p.removedAt == nil || removedAt.After(p.removedAt)) {
		p.removedAt = removedAt
		return true
	}
	return false
}
func (p *Counter) ValueType() CounterType {
	return p.valueType
}