Skip to content

Commit

Permalink
Merge pull request #868 from devlights/add-bitvector-example
Browse files Browse the repository at this point in the history
  • Loading branch information
devlights authored Oct 29, 2024
2 parents 32229a4 + 5448f09 commit 4d8b26a
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
8 changes: 8 additions & 0 deletions examples/singleapp/bitvector/Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# https://taskfile.dev

version: '3'

tasks:
default:
cmds:
- go run .
121 changes: 121 additions & 0 deletions examples/singleapp/bitvector/bitvector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"fmt"
"strings"
)

type (
// BitVector は、ビットベクタを表す構造体です.
BitVector struct {
bits []uint32
size int
}
kind int
)

const (
AND kind = iota
OR kind = iota
XOR kind = iota
)

// NewBitVector は、指定されたサイズのビットベクタを作成します.
func NewBitVector(size int) *BitVector {
return &BitVector{
bits: make([]uint32, (size+31)/32),
size: size,
}
}

// Set は、指定されたインデックス位置のビットを設定します.
func (me *BitVector) Set(index int, value bool) error {
if index < 0 || index >= me.size {
return fmt.Errorf("index out of range: %d", index)
}

var (
aryIndex = index / 32
bitIndex = uint(index % 32)
)
if value {
me.bits[aryIndex] |= 1 << bitIndex // ビットオン (OR)
} else {
me.bits[aryIndex] &^= 1 << bitIndex // ビットクリア (AND NOT)
}

return nil
}

// Get は、指定されたインデックス位置のビットを取得します.
func (me *BitVector) Get(index int) (bool, error) {
if index < 0 || index >= me.size {
return false, fmt.Errorf("index out of range: %d", index)
}

var (
aryIndex = index / 32
bitIndex = uint(index % 32)
bit = (me.bits[aryIndex] & (1 << bitIndex)) != 0
)

return bit, nil
}

// And は、指定された *BitVector とのAND結果を設定した新たな *BitVector を返します.
func (me *BitVector) And(other *BitVector) (*BitVector, error) {
return me.calc(other, AND)
}

// Or は、指定された *BitVector とのOR結果を設定した新たな *BitVector を返します.
func (me *BitVector) Or(other *BitVector) (*BitVector, error) {
return me.calc(other, OR)
}

// Xor は、指定された *BitVector とのXOR結果を設定した新たな *BitVector を返します.
func (me *BitVector) Xor(other *BitVector) (*BitVector, error) {
return me.calc(other, XOR)
}

func (me *BitVector) calc(other *BitVector, op kind) (*BitVector, error) {
if me.size != other.size {
return nil, fmt.Errorf("size mismatch: %d != %d", me.size, other.size)
}

var (
result = NewBitVector(me.size)
arySize = (me.size + 31) / 32
)
for i := range arySize {
switch op {
case AND:
result.bits[i] = me.bits[i] & other.bits[i]
case OR:
result.bits[i] = me.bits[i] | other.bits[i]
case XOR:
result.bits[i] = me.bits[i] ^ other.bits[i]
default:
return nil, fmt.Errorf("unknown kind: %d", op)
}
}

return result, nil
}

// String は、ビットベクタの文字列表現を返します.
func (me *BitVector) String() string {
var (
sb strings.Builder
val bool
)
for i := range me.size {
val, _ = me.Get(i)
if val {
sb.WriteRune('1')
} else {
sb.WriteRune('0')
}
}

return sb.String()
}
136 changes: 136 additions & 0 deletions examples/singleapp/bitvector/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package main

import (
"context"
"errors"
"log"
"time"
)

const (
MainTimeout = 100 * time.Millisecond
ProcTimeout = 500 * time.Microsecond
)

var (
ErrMainTooSlow = errors.New("[MAIN] TOO SLOW")
ErrProcTooSlow = errors.New("[PROC] TOO SLOW")
)

func init() {
log.SetFlags(0)
}

func main() {
var (
rootCtx = context.Background()
mainCtx, mainCxl = context.WithTimeoutCause(rootCtx, MainTimeout, ErrMainTooSlow)
procCtx = run(mainCtx)
err error
)
defer mainCxl()

select {
case <-mainCtx.Done():
err = context.Cause(mainCtx)
case <-procCtx.Done():
if err = context.Cause(procCtx); errors.Is(err, context.Canceled) {
err = nil
}
}

if err != nil {
log.Fatal(err)
}
}

func run(pCtx context.Context) context.Context {
var (
ctx, cxl = context.WithCancelCause(pCtx)
)

go func() {
cxl(proc(ctx))
}()
go func() {
<-time.After(ProcTimeout)
cxl(ErrProcTooSlow)
}()

return ctx
}

func proc(_ context.Context) error {
const (
bitSize = 32
)

//
// ビットの設定
//
var (
bv = NewBitVector(bitSize)
err error
)

for _, i := range []int{1, 3, 23} {
if err = bv.Set(i, true); err != nil {
return err
}
}
log.Printf("ORIG : %s", bv)

//
// ビットの取得
//
var (
bits []bool
bit bool
)

for _, i := range []int{1, 2, 3, 4} {
if bit, err = bv.Get(i); err != nil {
return err
}

bits = append(bits, bit)
}
log.Printf("BITS : %v", bits)

//
// 別のビットベクタとの演算
//
var (
bv2 = NewBitVector(bitSize)
bvAnd *BitVector
bvOr *BitVector
bvXor *BitVector
)

for _, i := range []int{2, 23, 24} {
if err = bv2.Set(i, true); err != nil {
return err
}
}
log.Printf("OTHER: %s", bv2)

// AND
if bvAnd, err = bv.And(bv2); err != nil {
return err
}
log.Printf("AND : %s", bvAnd)

// OR
if bvOr, err = bv.Or(bv2); err != nil {
return err
}
log.Printf("OR : %s", bvOr)

// XOR
if bvXor, err = bv.Xor(bv2); err != nil {
return err
}
log.Printf("XOR : %s", bvXor)

return nil
}

0 comments on commit 4d8b26a

Please sign in to comment.