<commit_before>/*
Copyright 2017 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Package spanner provides a client for reading and writing to Cloud Spanner
databases. See the packages under admin for clients that operate on databases
and instances.

See https://cloud.google.com/spanner/docs/getting-started/go/ for an
introduction to Cloud Spanner and additional help on using this API.

See https://godoc.org/cloud.google.com/go for authentication, timeouts,
connection pooling and similar aspects of this package.

Creating a Client

To start working with this package, create a client that refers to the database
of interest:

    ctx := context.Background()
    client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
    if err != nil {
        // TODO: Handle error.
    }
    defer client.Close()

Remember to close the client after use to free up the sessions in the session
pool.

Simple Reads and Writes

Two Client methods, Apply and Single, work well for simple reads and writes. As
a quick introduction, here we write a new row to the database and read it back:

    _, err := client.Apply(ctx, []*spanner.Mutation{
        spanner.Insert("Users",
            []string{"name", "email"},
            []interface{}{"alice", "a@example.com"})})
    if err != nil {
        // TODO: Handle error.
    }
    row, err := client.Single().ReadRow(ctx, "Users",
        spanner.Key{"alice"}, []string{"email"})
    if err != nil {
        // TODO: Handle error.
    }

All the methods used above are discussed in more detail below.

Keys

Every Cloud Spanner row has a unique key, composed of one or more columns.
Construct keys with a literal of type Key:

   key1 := spanner.Key{"alice"}

KeyRanges

The keys of a Cloud Spanner table are ordered. You can specify ranges of keys
using the KeyRange type:

    kr1 := spanner.KeyRange{Start: key1, End: key2}

By default, a KeyRange includes its start key but not its end key. Use
the Kind field to specify other boundary conditions:

    // include both keys
    kr2 := spanner.KeyRange{Start: key1, End: key2, Kind: spanner.ClosedClosed}

KeySets

A KeySet represents a set of keys. A single Key or KeyRange can act as a KeySet.
Use the KeySets function to build the union of several KeySets:

    ks1 := spanner.KeySets(key1, key2, kr1, kr2)

AllKeys returns a KeySet that refers to all the keys in a table:

    ks2 := spanner.AllKeys()

Transactions

All Cloud Spanner reads and writes occur inside transactions. There are two
types of transactions, read-only and read-write. Read-only transactions cannot
change the database, do not acquire locks, and may access either the current
database state or states in the past. Read-write transactions can read the
database before writing to it, and always apply to the most recent database
state.

Single Reads

The simplest and fastest transaction is a ReadOnlyTransaction that supports a
single read operation. Use Client.Single to create such a transaction. You can
chain the call to Single with a call to a Read method.

When you only want one row whose key you know, use ReadRow. Provide the table
name, key, and the columns you want to read:

    row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"})

Read multiple rows with the Read method. It takes a table name, KeySet, and list
of columns:

    iter := client.Single().Read(ctx, "Accounts", keyset1, columns)

Read returns a RowIterator. You can call the Do method on the iterator and pass
a callback:

    err := iter.Do(func(row *Row) error {
       // TODO: use row
       return nil
    })

RowIterator also follows the standard pattern for the Google
Cloud Client Libraries:

    defer iter.Stop()
    for {
        row, err := iter.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        // TODO: use row
    }

Always call Stop when you finish using an iterator this way, whether or not you
iterate to the end. (Failing to call Stop could lead you to exhaust the
database's session quota.)

To read rows with an index, use ReadUsingIndex.

Statements

The most general form of reading uses SQL statements. Construct a Statement
with NewStatement, setting any parameters using the Statement's Params map:

    stmt := spanner.NewStatement("SELECT First, Last FROM SINGERS WHERE Last >= @start")
    stmt.Params["start"] = "Dylan"

You can also construct a Statement directly with a struct literal, providing
your own map of parameters.

Use the Query method to run the statement and obtain an iterator:

    iter := client.Single().Query(ctx, stmt)

Rows

Once you have a Row, via an iterator or a call to ReadRow, you can extract
column values in several ways. Pass in a pointer to a Go variable of the
appropriate type when you extract a value.

You can extract by column position or name:

   err := row.Column(0, &name)
   err = row.ColumnByName("balance", &balance)

You can extract all the columns at once:

   err = row.Columns(&name, &balance)

Or you can define a Go struct that corresponds to your columns, and extract
into that:

   var s struct { Name string; Balance int64 }
   err = row.ToStruct(&s)

For Cloud Spanner columns that may contain NULL, use one of the NullXXX types,
like NullString:

    var ns spanner.NullString
    if err := row.Column(0, &ns); err != nil {
        // TODO: Handle error.
    }
    if ns.Valid {
        fmt.Println(ns.StringVal)
    } else {
        fmt.Println("column is NULL")
    }

Multiple Reads

To perform more than one read in a transaction, use ReadOnlyTransaction:

    txn := client.ReadOnlyTransaction()
    defer txn.Close()
    iter := txn.Query(ctx, stmt1)
    // ...
    iter =  txn.Query(ctx, stmt2)
    // ...

You must call Close when you are done with the transaction.

Timestamps and Timestamp Bounds

Cloud Spanner read-only transactions conceptually perform all their reads at a
single moment in time, called the transaction's read timestamp. Once a read has
started, you can call ReadOnlyTransaction's Timestamp method to obtain the read
timestamp.

By default, a transaction will pick the most recent time (a time where all
previously committed transactions are visible) for its reads. This provides the
freshest data, but may involve some delay. You can often get a quicker response
if you are willing to tolerate "stale" data. You can control the read timestamp
selected by a transaction by calling the WithTimestampBound method on the
transaction before using it. For example, to perform a query on data that is at
most one minute stale, use

    client.Single().
        WithTimestampBound(spanner.MaxStaleness(1*time.Minute)).
        Query(ctx, stmt)

See the documentation of TimestampBound for more details.

Mutations

To write values to a Cloud Spanner database, construct a Mutation. The spanner
package has functions for inserting, updating and deleting rows. Except for the
Delete methods, which take a Key or KeyRange, each mutation-building function
comes in three varieties.

One takes lists of columns and values along with the table name:

    m1 := spanner.Insert("Users",
        []string{"name", "email"},
        []interface{}{"alice", "a@example.com"})

One takes a map from column names to values:

    m2 := spanner.InsertMap("Users", map[string]interface{}{
        "name":  "alice",
        "email": "a@example.com",
    })

And the third accepts a struct value, and determines the columns from the
struct field names:

    type User struct { Name, Email string }
    u := User{Name: "alice", Email: "a@example.com"}
    m3, err := spanner.InsertStruct("Users", u)

Writes

To apply a list of mutations to the database, use Apply:

    _, err := client.Apply(ctx, []*spanner.Mutation{m1, m2, m3})

If you need to read before writing in a single transaction, use a
ReadWriteTransaction. ReadWriteTransactions may be aborted automatically by the
backend and need to be retried. You pass in a function to ReadWriteTransaction,
and the client will handle the retries automatically. Use the transaction's
BufferWrite method to buffer mutations, which will all be executed at the end
of the transaction:

    _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
        var balance int64
        row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"})
        if err != nil {
            // The transaction function will be called again if the error code
            // of this error is Aborted. The backend may automatically abort
            // any read/write transaction if it detects a deadlock or other
            // problems.
            return err
        }
        if err := row.Column(0, &balance); err != nil {
            return err
        }

        if balance <= 10 {
            return errors.New("insufficient funds in account")
        }
        balance -= 10
        m := spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance})
        // The buffered mutation will be committed.  If the commit
        // fails with an Aborted error, this function will be called
        // again.
        return txn.BufferWrite([]*spanner.Mutation{m})
    })

Structs

Cloud Spanner STRUCT (aka STRUCT) values
(https://cloud.google.com/spanner/docs/data-types#struct-type) can be
represented by a Go struct value.

A proto StructType is built from the field types and field tag information of
the Go struct. If a field in the struct type definition has a
"spanner:<field_name>" tag, then the value of the "spanner" key in the tag is
used as the name for that field in the built StructType, otherwise the field
name in the struct definition is used. To specify a field with an empty field
name in a Cloud Spanner STRUCT type, use the `spanner:""` tag annotation against
the corresponding field in the Go struct's type definition.

A STRUCT value can contain STRUCT-typed and Array-of-STRUCT typed fields and
these can be specified using named struct-typed and []struct-typed fields inside
a Go struct. However, embedded struct fields are not allowed. Unexported struct
fields are ignored.

NULL STRUCT values in Cloud Spanner are typed. A nil pointer to a Go struct
value can be used to specify a NULL STRUCT value of the corresponding
StructType.  Nil and empty slices of a Go STRUCT type can be used to specify
NULL and empty array values respectively of the corresponding StructType. A
slice of pointers to a Go struct type can be used to specify an array of
NULL-able STRUCT values.

DML and Partitioned DML

Spanner supports DML statements like INSERT, UPDATE and DELETE. Use
ReadWriteTransaction.Update to run DML statements. It returns the number of rows
affected. (You can call use ReadWriteTransaction.Query with a DML statement. The
first call to Next on the resulting RowIterator will return iterator.Done, and
the RowCount field of the iterator will hold the number of affected rows.)

For large databases, it may be more efficient to partition the DML statement.
Use client.PartitionedUpdate to run a DML statement in this way. Not all DML
statements can be partitioned.

Tracing

This client has been instrumented to use OpenCensus tracing
(http://opencensus.io). To enable tracing, see "Enabling Tracing for a Program"
at https://godoc.org/go.opencensus.io/trace. OpenCensus tracing requires Go 1.8
or higher.
*/
package spanner // import "cloud.google.com/go/spanner"

// clientUserAgent identifies the version of this package.
// It should be the same as https://pkg.go.dev/cloud.google.com/go/spanner.
// TODO: We will want to automate the version with a bash script.
const clientUserAgent = "spanner-go/v1.12.0"
<commit_msg>docs(spanner): add example for using SPANNER_EMULATOR_HOST (#4723)<commit_after>/*
Copyright 2017 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Package spanner provides a client for reading and writing to Cloud Spanner
databases. See the packages under admin for clients that operate on databases
and instances.

See https://cloud.google.com/spanner/docs/getting-started/go/ for an
introduction to Cloud Spanner and additional help on using this API.

See https://godoc.org/cloud.google.com/go for authentication, timeouts,
connection pooling and similar aspects of this package.

Creating a Client

To start working with this package, create a client that refers to the database
of interest:

    ctx := context.Background()
    client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
    if err != nil {
        // TODO: Handle error.
    }
    defer client.Close()

Remember to close the client after use to free up the sessions in the session
pool.

To use an emulator with this library, you can set the SPANNER_EMULATOR_HOST
environment variable to the address at which your emulator is running. This will
send requests to that address instead of to Cloud Spanner. You can then create
and use a client as usual:

    // Set SPANNER_EMULATOR_HOST environment variable.
    err := os.Setenv("SPANNER_EMULATOR_HOST", "localhost:9010")
    if err != nil {
        // TODO: Handle error.
    }
    // Create client as usual.
    client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
    if err != nil {
        // TODO: Handle error.
    }

Simple Reads and Writes

Two Client methods, Apply and Single, work well for simple reads and writes. As
a quick introduction, here we write a new row to the database and read it back:

    _, err := client.Apply(ctx, []*spanner.Mutation{
        spanner.Insert("Users",
            []string{"name", "email"},
            []interface{}{"alice", "a@example.com"})})
    if err != nil {
        // TODO: Handle error.
    }
    row, err := client.Single().ReadRow(ctx, "Users",
        spanner.Key{"alice"}, []string{"email"})
    if err != nil {
        // TODO: Handle error.
    }

All the methods used above are discussed in more detail below.

Keys

Every Cloud Spanner row has a unique key, composed of one or more columns.
Construct keys with a literal of type Key:

   key1 := spanner.Key{"alice"}

KeyRanges

The keys of a Cloud Spanner table are ordered. You can specify ranges of keys
using the KeyRange type:

    kr1 := spanner.KeyRange{Start: key1, End: key2}

By default, a KeyRange includes its start key but not its end key. Use
the Kind field to specify other boundary conditions:

    // include both keys
    kr2 := spanner.KeyRange{Start: key1, End: key2, Kind: spanner.ClosedClosed}

KeySets

A KeySet represents a set of keys. A single Key or KeyRange can act as a KeySet.
Use the KeySets function to build the union of several KeySets:

    ks1 := spanner.KeySets(key1, key2, kr1, kr2)

AllKeys returns a KeySet that refers to all the keys in a table:

    ks2 := spanner.AllKeys()

Transactions

All Cloud Spanner reads and writes occur inside transactions. There are two
types of transactions, read-only and read-write. Read-only transactions cannot
change the database, do not acquire locks, and may access either the current
database state or states in the past. Read-write transactions can read the
database before writing to it, and always apply to the most recent database
state.

Single Reads

The simplest and fastest transaction is a ReadOnlyTransaction that supports a
single read operation. Use Client.Single to create such a transaction. You can
chain the call to Single with a call to a Read method.

When you only want one row whose key you know, use ReadRow. Provide the table
name, key, and the columns you want to read:

    row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"})

Read multiple rows with the Read method. It takes a table name, KeySet, and list
of columns:

    iter := client.Single().Read(ctx, "Accounts", keyset1, columns)

Read returns a RowIterator. You can call the Do method on the iterator and pass
a callback:

    err := iter.Do(func(row *Row) error {
       // TODO: use row
       return nil
    })

RowIterator also follows the standard pattern for the Google
Cloud Client Libraries:

    defer iter.Stop()
    for {
        row, err := iter.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        // TODO: use row
    }

Always call Stop when you finish using an iterator this way, whether or not you
iterate to the end. (Failing to call Stop could lead you to exhaust the
database's session quota.)

To read rows with an index, use ReadUsingIndex.

Statements

The most general form of reading uses SQL statements. Construct a Statement
with NewStatement, setting any parameters using the Statement's Params map:

    stmt := spanner.NewStatement("SELECT First, Last FROM SINGERS WHERE Last >= @start")
    stmt.Params["start"] = "Dylan"

You can also construct a Statement directly with a struct literal, providing
your own map of parameters.

Use the Query method to run the statement and obtain an iterator:

    iter := client.Single().Query(ctx, stmt)

Rows

Once you have a Row, via an iterator or a call to ReadRow, you can extract
column values in several ways. Pass in a pointer to a Go variable of the
appropriate type when you extract a value.

You can extract by column position or name:

   err := row.Column(0, &name)
   err = row.ColumnByName("balance", &balance)

You can extract all the columns at once:

   err = row.Columns(&name, &balance)

Or you can define a Go struct that corresponds to your columns, and extract
into that:

   var s struct { Name string; Balance int64 }
   err = row.ToStruct(&s)

For Cloud Spanner columns that may contain NULL, use one of the NullXXX types,
like NullString:

    var ns spanner.NullString
    if err := row.Column(0, &ns); err != nil {
        // TODO: Handle error.
    }
    if ns.Valid {
        fmt.Println(ns.StringVal)
    } else {
        fmt.Println("column is NULL")
    }

Multiple Reads

To perform more than one read in a transaction, use ReadOnlyTransaction:

    txn := client.ReadOnlyTransaction()
    defer txn.Close()
    iter := txn.Query(ctx, stmt1)
    // ...
    iter =  txn.Query(ctx, stmt2)
    // ...

You must call Close when you are done with the transaction.

Timestamps and Timestamp Bounds

Cloud Spanner read-only transactions conceptually perform all their reads at a
single moment in time, called the transaction's read timestamp. Once a read has
started, you can call ReadOnlyTransaction's Timestamp method to obtain the read
timestamp.

By default, a transaction will pick the most recent time (a time where all
previously committed transactions are visible) for its reads. This provides the
freshest data, but may involve some delay. You can often get a quicker response
if you are willing to tolerate "stale" data. You can control the read timestamp
selected by a transaction by calling the WithTimestampBound method on the
transaction before using it. For example, to perform a query on data that is at
most one minute stale, use

    client.Single().
        WithTimestampBound(spanner.MaxStaleness(1*time.Minute)).
        Query(ctx, stmt)

See the documentation of TimestampBound for more details.

Mutations

To write values to a Cloud Spanner database, construct a Mutation. The spanner
package has functions for inserting, updating and deleting rows. Except for the
Delete methods, which take a Key or KeyRange, each mutation-building function
comes in three varieties.

One takes lists of columns and values along with the table name:

    m1 := spanner.Insert("Users",
        []string{"name", "email"},
        []interface{}{"alice", "a@example.com"})

One takes a map from column names to values:

    m2 := spanner.InsertMap("Users", map[string]interface{}{
        "name":  "alice",
        "email": "a@example.com",
    })

And the third accepts a struct value, and determines the columns from the
struct field names:

    type User struct { Name, Email string }
    u := User{Name: "alice", Email: "a@example.com"}
    m3, err := spanner.InsertStruct("Users", u)

Writes

To apply a list of mutations to the database, use Apply:

    _, err := client.Apply(ctx, []*spanner.Mutation{m1, m2, m3})

If you need to read before writing in a single transaction, use a
ReadWriteTransaction. ReadWriteTransactions may be aborted automatically by the
backend and need to be retried. You pass in a function to ReadWriteTransaction,
and the client will handle the retries automatically. Use the transaction's
BufferWrite method to buffer mutations, which will all be executed at the end
of the transaction:

    _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
        var balance int64
        row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"})
        if err != nil {
            // The transaction function will be called again if the error code
            // of this error is Aborted. The backend may automatically abort
            // any read/write transaction if it detects a deadlock or other
            // problems.
            return err
        }
        if err := row.Column(0, &balance); err != nil {
            return err
        }

        if balance <= 10 {
            return errors.New("insufficient funds in account")
        }
        balance -= 10
        m := spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance})
        // The buffered mutation will be committed.  If the commit
        // fails with an Aborted error, this function will be called
        // again.
        return txn.BufferWrite([]*spanner.Mutation{m})
    })

Structs

Cloud Spanner STRUCT (aka STRUCT) values
(https://cloud.google.com/spanner/docs/data-types#struct-type) can be
represented by a Go struct value.

A proto StructType is built from the field types and field tag information of
the Go struct. If a field in the struct type definition has a
"spanner:<field_name>" tag, then the value of the "spanner" key in the tag is
used as the name for that field in the built StructType, otherwise the field
name in the struct definition is used. To specify a field with an empty field
name in a Cloud Spanner STRUCT type, use the `spanner:""` tag annotation against
the corresponding field in the Go struct's type definition.

A STRUCT value can contain STRUCT-typed and Array-of-STRUCT typed fields and
these can be specified using named struct-typed and []struct-typed fields inside
a Go struct. However, embedded struct fields are not allowed. Unexported struct
fields are ignored.

NULL STRUCT values in Cloud Spanner are typed. A nil pointer to a Go struct
value can be used to specify a NULL STRUCT value of the corresponding
StructType.  Nil and empty slices of a Go STRUCT type can be used to specify
NULL and empty array values respectively of the corresponding StructType. A
slice of pointers to a Go struct type can be used to specify an array of
NULL-able STRUCT values.

DML and Partitioned DML

Spanner supports DML statements like INSERT, UPDATE and DELETE. Use
ReadWriteTransaction.Update to run DML statements. It returns the number of rows
affected. (You can call use ReadWriteTransaction.Query with a DML statement. The
first call to Next on the resulting RowIterator will return iterator.Done, and
the RowCount field of the iterator will hold the number of affected rows.)

For large databases, it may be more efficient to partition the DML statement.
Use client.PartitionedUpdate to run a DML statement in this way. Not all DML
statements can be partitioned.

Tracing

This client has been instrumented to use OpenCensus tracing
(http://opencensus.io). To enable tracing, see "Enabling Tracing for a Program"
at https://godoc.org/go.opencensus.io/trace. OpenCensus tracing requires Go 1.8
or higher.
*/
package spanner // import "cloud.google.com/go/spanner"

// clientUserAgent identifies the version of this package.
// It should be the same as https://pkg.go.dev/cloud.google.com/go/spanner.
// TODO: We will want to automate the version with a bash script.
const clientUserAgent = "spanner-go/v1.12.0"
<|endoftext|>


<commit_before>package kite

import (
	"testing"
)

func testSplitVersion(t *testing.T) {
	name, version, err := splitVersion("asdf-1.2.3")
	if err != nil {
		t.Error(err)
	}
	if name != "asdf" {
		t.Error("Name is not ok:", name)
	}
	if version != "1.2.3" {
		t.Error("Version is not ok:", version)
	}

	name, version, err = splitVersion("asdf")
	if err == nil {
		t.Error(err)
	}
}
<commit_msg>fix a test<commit_after>package kite

import (
	"testing"
)

func testSplitVersion(t *testing.T) {
	name, version, err := splitVersion("asdf-1.2.3", false)
	if err != nil {
		t.Error(err)
	}
	if name != "asdf" {
		t.Error("Name is not ok:", name)
	}
	if version != "1.2.3" {
		t.Error("Version is not ok:", version)
	}

	name, version, err = splitVersion("asdf", false)
	if err == nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"
)

// Example of simple function with two arguments
func print(prefix, data string) {
	fmt.Printf("Function %-20v: %v\n", prefix , data)
}

// Example of variable count of arguments
func concatenation(arguments ...string) string {
	result := ""
	for _, part := range arguments {
		result += part
	}

	return result
}

// Example of recursive function
//
// pow(2, 5) > pow(2, 4) > pow(2, 3) > pow(2, 2) > pow(2, 1)
// 2 * 16    < 2 * 8     < 2 * 4     < 2 * 2     < 2
func pow(number int, degree uint) int {
	if degree <= 1 {
		return number
	}

	return number * pow(number, degree - 1)
}

// Example of function as result of another function
func wrap(wrapSymbols string) (func(data string) string) {
	return func(data string) string {
		return wrapSymbols + data + wrapSymbols
	}
}

// Example of using functions as arguments
func stringConverter(data string, middlewareList ...func (data string) string) string {
	for _, middleware := range middlewareList {
		data = middleware(data)
	}

	return data
}

func main () {
	print("print", "some data")

	print("concatenation", concatenation("a", "b", "c", "d"))

	aliasOfConcatenation := concatenation

	print("aliasOfConcatenation", aliasOfConcatenation("alias", " ", "of", " ", "concatenation"))

	print("pow", strconv.Itoa(pow(2, 5)))

	print("wrap", wrap("|")("wrap me"))

	print("stringConverter", stringConverter("	\n\t SoMe tExT\n\r\t  ", strings.ToLower, strings.TrimSpace, wrap("@")))
}
<commit_msg>fix lesson_15_function<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"
)

// Example of simple function with two arguments
func print(funcName, data string) {
	fmt.Printf("Function %-20v: %v\n", funcName , data)
}

// Example of variable count of arguments
func concatenation(arguments ...string) string {
	result := ""
	for _, part := range arguments {
		result += part
	}

	return result
}

// Example of recursive function
//
// pow(2, 5) > pow(2, 4) > pow(2, 3) > pow(2, 2) > pow(2, 1)
// 2 * 16    < 2 * 8     < 2 * 4     < 2 * 2     < 2
func pow(number int, degree uint) int {
	if degree <= 1 {
		return number
	}

	return number * pow(number, degree - 1)
}

// Example of function as result of another function
func wrap(wrapSymbols string) (func(data string) string) {
	return func(data string) string {
		return wrapSymbols + data + wrapSymbols
	}
}

// Example of using functions as arguments
func stringConverter(data string, middlewareList ...func (data string) string) string {
	for _, middleware := range middlewareList {
		data = middleware(data)
	}

	return data
}

func main () {
	print("print", "some data")

	print("concatenation", concatenation("a", "b", "c", "d"))

	aliasOfConcatenation := concatenation

	print("aliasOfConcatenation", aliasOfConcatenation("alias", " ", "of", " ", "concatenation"))

	print("pow", strconv.Itoa(pow(2, 5)))

	print("wrap", wrap("|")("wrap me"))

	print("stringConverter", stringConverter("	\n\t SoMe tExT\n\r\t  ", strings.ToLower, strings.TrimSpace, wrap("@")))
}
<|endoftext|>


<commit_before>package core

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	expandedDicts []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i].value, ps[i+1:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{
		positionals:   ts,
		expandedList:  l,
		keywords:      ks,
		expandedDicts: expandedDicts,
	}
}

func mergeRestPositionalArgs(t *Thunk, ps ...PositionalArgument) *Thunk {
	for _, p := range ps {
		if p.expanded {
			t = PApp(Merge, t, p.value)
		} else {
			t = PApp(
				NewLazyFunction(appendFuncSignature, appendFunc), // Avoid initialization loop
				t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ps := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ps...)
	}

	return PApp(Merge, NewList(ps...), l)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

		if v, ok := d.Search(k); ok {
			new := make([]*Thunk, len(args.expandedDicts))
			copy(new, args.expandedDicts)
			new[i] = Normal(d.Remove(k))
			args.expandedDicts = new
			return v
		}
	}

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	defer func() {
		args.keywords = nil
		args.expandedDicts = nil
	}()

	t := EmptyDictionary

	for _, k := range args.keywords {
		t = PApp(Insert, t, NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = PApp(Merge, t, tt)
	}

	return t
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(merged Arguments) Arguments {
	var new Arguments

	if new.expandedList == nil {
		new.positionals = append(args.positionals, merged.positionals...)
		new.expandedList = merged.expandedList
	} else {
		new.positionals = args.positionals
		new.expandedList = PApp(
			Append,
			append([]*Thunk{args.expandedList}, merged.positionals...)...)

		if merged.expandedList != nil {
			new.expandedList = PApp(Merge, new.expandedList, merged.expandedList)
		}
	}

	new.keywords = append(args.keywords, merged.keywords...)
	new.expandedDicts = append(args.expandedDicts, merged.expandedDicts...)

	return new
}

func (args Arguments) empty() *Thunk {
	if args.positionals != nil && len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

	if args.expandedDicts != nil {
		for _, t := range args.expandedDicts {
			v := t.Eval()
			d, ok := v.(DictionaryType)

			if !ok {
				return NotDictionaryError(v)
			}

			n += d.Size()
		}
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<commit_msg>Refactor NewArguments()<commit_after>package core

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	ds []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i].value, ps[i+1:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{ts, l, ks, ds}
}

func mergeRestPositionalArgs(t *Thunk, ps ...PositionalArgument) *Thunk {
	for _, p := range ps {
		if p.expanded {
			t = PApp(Merge, t, p.value)
		} else {
			t = PApp(
				NewLazyFunction(appendFuncSignature, appendFunc), // Avoid initialization loop
				t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ps := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ps...)
	}

	return PApp(Merge, NewList(ps...), l)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

		if v, ok := d.Search(k); ok {
			new := make([]*Thunk, len(args.expandedDicts))
			copy(new, args.expandedDicts)
			new[i] = Normal(d.Remove(k))
			args.expandedDicts = new
			return v
		}
	}

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	defer func() {
		args.keywords = nil
		args.expandedDicts = nil
	}()

	t := EmptyDictionary

	for _, k := range args.keywords {
		t = PApp(Insert, t, NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = PApp(Merge, t, tt)
	}

	return t
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(merged Arguments) Arguments {
	var new Arguments

	if new.expandedList == nil {
		new.positionals = append(args.positionals, merged.positionals...)
		new.expandedList = merged.expandedList
	} else {
		new.positionals = args.positionals
		new.expandedList = PApp(
			Append,
			append([]*Thunk{args.expandedList}, merged.positionals...)...)

		if merged.expandedList != nil {
			new.expandedList = PApp(Merge, new.expandedList, merged.expandedList)
		}
	}

	new.keywords = append(args.keywords, merged.keywords...)
	new.expandedDicts = append(args.expandedDicts, merged.expandedDicts...)

	return new
}

func (args Arguments) empty() *Thunk {
	if args.positionals != nil && len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

	if args.expandedDicts != nil {
		for _, t := range args.expandedDicts {
			v := t.Eval()
			d, ok := v.(DictionaryType)

			if !ok {
				return NotDictionaryError(v)
			}

			n += d.Size()
		}
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"fmt"
	// "argon/src/scanner"
)

func main() {
	currentLine  := 0
	currentColl  := 0
	sourceIndex  := 0
	indexing     := false
	indexerStart := 0
	tracker      := 0
	const_string_mode := false;
	cookieJar    := []string{}
	file, err    := ioutil.ReadFile("../testfiles/main.ar")
	lexedToken   := &token{"0",0,0,0,"0"}
	if err != nil {
		panic(err)
	}
	for i := 0; i < len(string(file)); i++ {

		char := GET("../testFiles/main.ar", currentColl, currentLine, sourceIndex);

    lexedToken = lex(char);

		//this handles reading out non-string constants

		if lexedToken.tokenType == "STRING" || lexedToken.tokenType == "STRING_CONSTANT"{

			if(!indexing){

				indexerStart = lexedToken.sourceIndex;

			}

			if(lexedToken.tokenType == "STRING_CONSTANT"){
				const_string_mode = true;
				fmt.Println("found a \" ")
			}

			indexing = true;
			tracker++;

		}else if(indexing && const_string_mode){
			fmt.Println("indexing and const_string_mode are true")
				if(lexedToken.tokenType == "STRING_CONSTANT"){

					cookieJar = append(cookieJar, concatCookie(StackCookies([]int{indexerStart,tracker,indexerStart+tracker-1,lexedToken.lineIndex})))
					fmt.Println("indexing and const_string_mode and tokenType == STRING_CONSTANT")
					tracker = 0;
					indexerStart = 0;
					indexing = false;
					const_string_mode = false;
				}
	}else if(indexing && !const_string_mode){
		cookieJar = append(cookieJar, concatCookie(StackCookies([]int{indexerStart,tracker,indexerStart+tracker-1,lexedToken.lineIndex})))
		fmt.Println("tracker for append = ", tracker);
		tracker = 0;
		indexerStart = 0;
		indexing = false;
	}

		if char.cargo == "NEWLINE" {
			currentLine += 1
			currentColl = 0
		}

		sourceIndex += 1
		currentColl += 1

		}
		//test. remove once we confirm it works
		for i := 0; i < len(cookieJar); i++ {
			fmt.Println(cookieJar[i])
		}
	}

//this function is for the parser to request tokens from the lexer.
// func eat(tokenList []string, TkIndex int) *token{
//
// }

func lex(char *char) *token {

	//if the char is a letter
  if(isIn(char.cargo, IDENTIFIER_STARTCHARS())){

		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"STRING"}

	}else if(isIn(char.cargo, NUMBER_CHARS())){

		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"INTEGER"}

	}else if(isIn(char.cargo, STRING_CHARACTERS())){

			return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"STRING_CONSTANT"}

	}else if(isIn(char.cargo, ONE_CHARACTER_SYMBOLS())){

			return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"SYMBOL"}

	}
		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"ERROR"}

}

func isIn(character string, section []string) bool{
  for i := 0; i < len(section); i++ {
    if section[i] == character{
    return true
		}
	}
	return false
}

func StackCookies(r []int) []string{
	cookieStack := []string{}

	for i := 0; i < r[1]; i++ {

		//cookies in the cookieJar are listed as follows : indexerStart /
		//																								 tracker			/
		//																					indexerStart + tracker -1 /
		//																								line 					/
		cookieStack = append(cookieStack, GET("../testfiles/main.ar", r[0]+i, r[3], r[0]+i).cargo);
				fmt.Println("adding : ", GET("../testfiles/main.ar", r[0]+i, r[3], r[0]+i).cargo, "to stack. stack is now" , cookieStack);
	}
	fmt.Println("SC output : " , cookieStack);
	return cookieStack;
}

//function to hang a type to concatenated or constant strings;
// func validate(toValidate string) {
//
// }

//function for concatinating cookies
func concatCookie(r []string) string {
	f := "";
	for i := 0; i < len(r); i++ {
		f += r[i];
	}
	// fmt.Println("outputted : ", f );
	return f;
}
<commit_msg>lexer can now also read string constants<commit_after>package main

import (
	"io/ioutil"
	"fmt"
	// "argon/src/scanner"
)

func main() {
	currentLine  := 0
	currentColl  := 0
	sourceIndex  := 0
	indexing     := false
	indexerStart := 0
	tracker      := 0
	const_string_mode := false;
	cookieJar    := []string{}
	file, err    := ioutil.ReadFile("../testfiles/main.ar")
	lexedToken   := &token{"0",0,0,0,"0"}
	if err != nil {
		panic(err)
	}
	for i := 0; i < len(string(file)); i++ {

		char := GET("../testFiles/main.ar", currentColl, currentLine, sourceIndex);

    lexedToken = lex(char);

		//this handles reading out non-string constants

		if lexedToken.tokenType == "STRING" || lexedToken.tokenType == "STRING_CONSTANT" && !const_string_mode{

			if(!indexing){
				indexerStart = lexedToken.sourceIndex;
			}

			if(lexedToken.tokenType == "STRING_CONSTANT"){
				const_string_mode = true;
				fmt.Println("found a \" ")
			}

			indexing = true;
			tracker++;

		}else if(indexing && const_string_mode){
			tracker++
				if(lexedToken.tokenType == "STRING_CONSTANT"){

					cookieJar = append(cookieJar, concatCookie(StackCookies([]int{indexerStart,tracker,indexerStart+tracker-1,lexedToken.lineIndex})))
					fmt.Println("indexing and const_string_mode and tokenType == STRING_CONSTANT")
					tracker = 0;
					indexerStart = 0;
					indexing = false;
					const_string_mode = false;
				}
	}else if(indexing && !const_string_mode){
		cookieJar = append(cookieJar, concatCookie(StackCookies([]int{indexerStart,tracker,indexerStart+tracker-1,lexedToken.lineIndex})))
		fmt.Println("tracker for append = ", tracker);
		tracker = 0;
		indexerStart = 0;
		indexing = false;
	}

		if char.cargo == "NEWLINE" {
			currentLine += 1
			currentColl = 0
		}

		sourceIndex += 1
		currentColl += 1

		}
		//test. remove once we confirm it works
		for i := 0; i < len(cookieJar); i++ {
			fmt.Println(cookieJar[i])
		}
	}

//this function is for the parser to request tokens from the lexer.
// func eat(tokenList []string, TkIndex int) *token{
//
// }

func lex(char *char) *token {

	//if the char is a letter
  if(isIn(char.cargo, IDENTIFIER_STARTCHARS())){

		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"STRING"}

	}else if(isIn(char.cargo, NUMBER_CHARS())){

		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"INTEGER"}

	}else if(isIn(char.cargo, STRING_CHARACTERS())){

			return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"STRING_CONSTANT"}

	}else if(isIn(char.cargo, ONE_CHARACTER_SYMBOLS())){

			return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"SYMBOL"}

	}
		return &token{char.cargo,char.sourceIndex,char.lineIndex,char.colIndex,"ERROR"}

}

func isIn(character string, section []string) bool{
  for i := 0; i < len(section); i++ {
    if section[i] == character{
    return true
		}
	}
	return false
}

func StackCookies(r []int) []string{
	cookieStack := []string{}

	for i := 0; i < r[1]; i++ {

		//cookies in the cookieJar are listed as follows : indexerStart /
		//																								 tracker			/
		//																					indexerStart + tracker -1 /
		//																								line 					/
		cookieStack = append(cookieStack, GET("../testfiles/main.ar", r[0]+i, r[3], r[0]+i).cargo);
				fmt.Println("adding : ", GET("../testfiles/main.ar", r[0]+i, r[3], r[0]+i).cargo, "to stack. stack is now" , cookieStack);
	}
	fmt.Println("SC output : " , cookieStack);
	return cookieStack;
}

//function to hang a type to concatenated or constant strings;
// func validate(toValidate string) {
//
// }

//function for concatinating cookies
func concatCookie(r []string) string {
	f := "";
	for i := 0; i < len(r); i++ {
		f += r[i];
	}
	// fmt.Println("outputted : ", f );
	return f;
}
<|endoftext|>


<commit_before>/*
 * find-fast
 *
 * Walks a file system hierarchy using this library.
 */
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"

	"github.com/karrick/godirwalk"
	"github.com/karrick/golf"
	"github.com/mattn/go-isatty"
)

var NoColor = os.Getenv("TERM") == "dumb" || !(isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()))

func main() {
	optRegex := golf.String("regex", "", "Do not print unless full path matches regex.")
	optQuiet := golf.Bool("quiet", false, "Do not print intermediate errors to stderr.")
	golf.Parse()

	programName, err := os.Executable()
	if err != nil {
		programName = os.Args[0]
	}
	programName = filepath.Base(programName)

	var nameRE *regexp.Regexp
	if *optRegex != "" {
		nameRE, err = regexp.Compile(*optRegex)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: invalid regex pattern: %s\n", programName, err)
			os.Exit(2)
		}
	}

	var buf []byte // only used when color output

	options := &godirwalk.Options{
		ErrorCallback: func(osPathname string, err error) godirwalk.ErrorAction {
			if !*optQuiet {
				fmt.Fprintf(os.Stderr, "%s: %s\n", programName, err)
			}
			return godirwalk.SkipNode
		},
		Unsorted: true,
	}

	switch {
	case nameRE == nil:
		// When no name pattern provided, print everything.
		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			_, err := fmt.Println(osPathname)
			return err
		}
	case NoColor:
		// Name pattern was provided, but color not permitted.
		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			var err error
			if nameRE.FindString(osPathname) != "" {
				_, err = fmt.Println(osPathname)
			}
			return err
		}
	default:
		// Name pattern provided, and color is permitted.
		buf = append(buf, "\033[22m"...) // very first print should set normal intensity

		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			matches := nameRE.FindAllStringSubmatchIndex(osPathname, -1)
			if len(matches) == 0 {
				return nil // entry does not match pattern
			}

			var prev int
			for _, tuple := range matches {
				buf = append(buf, osPathname[prev:tuple[0]]...)     // print text before match
				buf = append(buf, "\033[1m"...)                     // bold intensity
				buf = append(buf, osPathname[tuple[0]:tuple[1]]...) // print match
				buf = append(buf, "\033[22m"...)                    // normal intensity
				prev = tuple[1]
			}

			buf = append(buf, osPathname[prev:]...)      // print remaining text after final match
			_, err := os.Stdout.Write(append(buf, '\n')) // don't forget newline
			buf = buf[:0]                                // reset buffer for next string
			return err
		}
	}

	dirname := "."
	if golf.NArg() > 0 {
		dirname = golf.Arg(0)
	}

	if err = godirwalk.Walk(dirname, options); err != nil {
		fmt.Fprintf(os.Stderr, "%s: %s\n", programName, err)
		os.Exit(1)
	}
}
<commit_msg>find-fast provides `--skip PATTERN` to skip entries<commit_after>/*
 * find-fast
 *
 * Walks a file system hierarchy using this library.
 */
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/karrick/godirwalk"
	"github.com/karrick/golf"
	"github.com/mattn/go-isatty"
)

var NoColor = os.Getenv("TERM") == "dumb" || !(isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()))

func main() {
	optQuiet := golf.Bool("quiet", false, "Do not print intermediate errors to stderr.")
	optRegex := golf.String("regex", "", "Do not print unless full path matches regex.")
	optSkip := golf.String("skip", "", "Skip and do not descend into entries with this substring in the pathname")
	golf.Parse()

	programName, err := os.Executable()
	if err != nil {
		programName = os.Args[0]
	}
	programName = filepath.Base(programName)

	var nameRE *regexp.Regexp
	if *optRegex != "" {
		nameRE, err = regexp.Compile(*optRegex)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: invalid regex pattern: %s\n", programName, err)
			os.Exit(2)
		}
	}

	var buf []byte // only used when color output

	options := &godirwalk.Options{
		ErrorCallback: func(osPathname string, err error) godirwalk.ErrorAction {
			if !*optQuiet {
				fmt.Fprintf(os.Stderr, "%s: %s\n", programName, err)
			}
			return godirwalk.SkipNode
		},
		Unsorted: true,
	}

	switch {
	case nameRE == nil:
		// When no name pattern provided, print everything.
		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			if *optSkip != "" && strings.Contains(osPathname, ".git") {
				return filepath.SkipDir
			}
			_, err := fmt.Println(osPathname)
			return err
		}
	case NoColor:
		// Name pattern was provided, but color not permitted.
		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			if *optSkip != "" && strings.Contains(osPathname, ".git") {
				return filepath.SkipDir
			}
			var err error
			if nameRE.FindString(osPathname) != "" {
				_, err = fmt.Println(osPathname)
			}
			return err
		}
	default:
		// Name pattern provided, and color is permitted.
		buf = append(buf, "\033[22m"...) // very first print should set normal intensity

		options.Callback = func(osPathname string, _ *godirwalk.Dirent) error {
			if *optSkip != "" && strings.Contains(osPathname, ".git") {
				return filepath.SkipDir
			}
			matches := nameRE.FindAllStringSubmatchIndex(osPathname, -1)
			if len(matches) == 0 {
				return nil // entry does not match pattern
			}

			var prev int
			for _, tuple := range matches {
				buf = append(buf, osPathname[prev:tuple[0]]...)     // print text before match
				buf = append(buf, "\033[1m"...)                     // bold intensity
				buf = append(buf, osPathname[tuple[0]:tuple[1]]...) // print match
				buf = append(buf, "\033[22m"...)                    // normal intensity
				prev = tuple[1]
			}

			buf = append(buf, osPathname[prev:]...)      // print remaining text after final match
			_, err := os.Stdout.Write(append(buf, '\n')) // don't forget newline
			buf = buf[:0]                                // reset buffer for next string
			return err
		}
	}

	dirname := "."
	if golf.NArg() > 0 {
		dirname = golf.Arg(0)
	}

	if err = godirwalk.Walk(dirname, options); err != nil {
		fmt.Fprintf(os.Stderr, "%s: %s\n", programName, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// +build darwin

package memory

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"
)

// Get memory statistics
func Get() (*Stats, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Reference: man 1 vm_stat
	cmd := exec.CommandContext(ctx, "vm_stat")
	out, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	memory, err := collectMemoryStats(out)
	if err != nil {
		go cmd.Wait()
		return nil, err
	}
	if err := cmd.Wait(); err != nil {
		return nil, err
	}

	// Reference: sys/sysctl.h, man 3 sysctl, sysctl vm.swapusage
	ret, err := unix.SysctlRaw("vm.swapusage")
	if err != nil {
		return nil, fmt.Errorf("failed in sysctl vm.swapusage: %s", err)
	}
	swap, err := collectSwapStats(ret)
	if err != nil {
		return nil, err
	}
	memory.SwapTotal = swap.Total
	memory.SwapUsed = swap.Used
	memory.SwapFree = swap.Avail

	return memory, nil
}

// Stats represents memory statistics for darwin
type Stats struct {
	Total, Used, Cached, Free, Active, Inactive, SwapTotal, SwapUsed, SwapFree uint64
}

// References:
//   - https://support.apple.com/en-us/HT201464#memory
//   - https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemoryStats/Articles/AboutMemoryStats.html
//   - https://opensource.apple.com/source/system_cmds/system_cmds-790/vm_stat.tproj/
func collectMemoryStats(out io.Reader) (*Stats, error) {
	scanner := bufio.NewScanner(out)
	if !scanner.Scan() {
		return nil, fmt.Errorf("failed to scan output of vm_stat")
	}
	line := scanner.Text()
	var pageSize uint64
	if _, err := fmt.Sscanf(line, "Mach Virtual Memory Statistics: (page size of %d bytes)", &pageSize); err != nil {
		return nil, fmt.Errorf("unexpected output of vm_stat: %s", line)
	}

	var memory Stats
	var speculative, wired, purgeable, fileBacked, compressed uint64
	memStats := map[string]*uint64{
		"Pages free":                   &memory.Free,
		"Pages active":                 &memory.Active,
		"Pages inactive":               &memory.Inactive,
		"Pages speculative":            &speculative,
		"Pages wired down":             &wired,
		"Pages purgeable":              &purgeable,
		"File-backed pages":            &fileBacked,
		"Pages occupied by compressor": &compressed,
	}
	for scanner.Scan() {
		line := scanner.Text()
		i := strings.IndexRune(line, ':')
		if i < 0 {
			continue
		}
		if ptr := memStats[line[:i]]; ptr != nil {
			val := strings.TrimRight(strings.TrimSpace(line[i+1:]), ".")
			if v, err := strconv.ParseUint(val, 10, 64); err == nil {
				*ptr = v * pageSize
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("scan error for vm_stat: %s", err)
	}

	memory.Cached = purgeable + fileBacked
	memory.Used = wired + compressed + memory.Active + memory.Inactive + speculative - memory.Cached
	memory.Total = memory.Used + memory.Cached + memory.Free
	return &memory, nil
}

// xsw_usage in sys/sysctl.h
type swapUsage struct {
	Total     uint64
	Avail     uint64
	Used      uint64
	Pagesize  int32
	Encrypted bool
}

func collectSwapStats(out []byte) (*swapUsage, error) {
	if len(out) != 32 {
		return nil, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", out, len(out))
	}
	return (*swapUsage)(unsafe.Pointer(&out[0])), nil
}
<commit_msg>update references<commit_after>// +build darwin

package memory

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"
)

// Get memory statistics
func Get() (*Stats, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Reference: man 1 vm_stat
	cmd := exec.CommandContext(ctx, "vm_stat")
	out, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	memory, err := collectMemoryStats(out)
	if err != nil {
		go cmd.Wait()
		return nil, err
	}
	if err := cmd.Wait(); err != nil {
		return nil, err
	}

	// Reference: sys/sysctl.h, man 3 sysctl, sysctl vm.swapusage
	ret, err := unix.SysctlRaw("vm.swapusage")
	if err != nil {
		return nil, fmt.Errorf("failed in sysctl vm.swapusage: %s", err)
	}
	swap, err := collectSwapStats(ret)
	if err != nil {
		return nil, err
	}
	memory.SwapTotal = swap.Total
	memory.SwapUsed = swap.Used
	memory.SwapFree = swap.Avail

	return memory, nil
}

// Stats represents memory statistics for darwin
type Stats struct {
	Total, Used, Cached, Free, Active, Inactive, SwapTotal, SwapUsed, SwapFree uint64
}

// References:
//   - https://support.apple.com/guide/activity-monitor/view-memory-usage-actmntr1004/10.14/mac/11.0
//   - https://opensource.apple.com/source/system_cmds/system_cmds-880.60.2/vm_stat.tproj/
func collectMemoryStats(out io.Reader) (*Stats, error) {
	scanner := bufio.NewScanner(out)
	if !scanner.Scan() {
		return nil, fmt.Errorf("failed to scan output of vm_stat")
	}
	line := scanner.Text()
	var pageSize uint64
	if _, err := fmt.Sscanf(line, "Mach Virtual Memory Statistics: (page size of %d bytes)", &pageSize); err != nil {
		return nil, fmt.Errorf("unexpected output of vm_stat: %s", line)
	}

	var memory Stats
	var speculative, wired, purgeable, fileBacked, compressed uint64
	memStats := map[string]*uint64{
		"Pages free":                   &memory.Free,
		"Pages active":                 &memory.Active,
		"Pages inactive":               &memory.Inactive,
		"Pages speculative":            &speculative,
		"Pages wired down":             &wired,
		"Pages purgeable":              &purgeable,
		"File-backed pages":            &fileBacked,
		"Pages occupied by compressor": &compressed,
	}
	for scanner.Scan() {
		line := scanner.Text()
		i := strings.IndexRune(line, ':')
		if i < 0 {
			continue
		}
		if ptr := memStats[line[:i]]; ptr != nil {
			val := strings.TrimRight(strings.TrimSpace(line[i+1:]), ".")
			if v, err := strconv.ParseUint(val, 10, 64); err == nil {
				*ptr = v * pageSize
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("scan error for vm_stat: %s", err)
	}

	memory.Cached = purgeable + fileBacked
	memory.Used = wired + compressed + memory.Active + memory.Inactive + speculative - memory.Cached
	memory.Total = memory.Used + memory.Cached + memory.Free
	return &memory, nil
}

// xsw_usage in sys/sysctl.h
type swapUsage struct {
	Total     uint64
	Avail     uint64
	Used      uint64
	Pagesize  int32
	Encrypted bool
}

func collectSwapStats(out []byte) (*swapUsage, error) {
	if len(out) != 32 {
		return nil, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", out, len(out))
	}
	return (*swapUsage)(unsafe.Pointer(&out[0])), nil
}
<|endoftext|>


<commit_before>package text

import (
	"image"
	"image/color"
	"image/draw"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

type Text struct {
	Orig pixel.Vec
	Dot  pixel.Vec

	atlas *Atlas

	color      pixel.RGBA
	lineHeight float64
	tabWidth   float64

	prevR rune
	glyph pixel.TrianglesData
	tris  pixel.TrianglesData
	d     pixel.Drawer
	trans *pixel.Batch
}

func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	atlas := NewAtlas(face, runes)

	txt := &Text{
		atlas:      atlas,
		color:      pixel.Alpha(1),
		lineHeight: 1,
		tabWidth:   atlas.mapping[' '].Advance * 4,
	}
	txt.glyph.SetLen(6)
	txt.d.Picture = txt.atlas.pic
	txt.d.Triangles = &txt.tris
	txt.trans = pixel.NewBatch(&pixel.TrianglesData{}, atlas.pic)

	txt.Clear()

	return txt
}

func (txt *Text) Atlas() *Atlas {
	return txt.atlas
}

func (txt *Text) SetMatrix(m pixel.Matrix) {
	txt.trans.SetMatrix(m)
}

func (txt *Text) SetColorMask(c color.Color) {
	txt.trans.SetColorMask(c)
}

func (txt *Text) Color(c color.Color) {
	txt.color = pixel.ToRGBA(c)
}

func (txt *Text) LineHeight(scale float64) {
	txt.lineHeight = scale
}

func (txt *Text) TabWidth(width float64) {
	txt.tabWidth = width
}

func (txt *Text) Clear() {
	txt.prevR = -1
	txt.tris.SetLen(0)
	txt.d.Dirty()
}

func (txt *Text) Write(p []byte) (n int, err error) {
	n, err = len(p), nil // always returns this

	if len(p) == 0 {
		return
	}

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for len(p) > 0 {
		r, size := utf8.DecodeRune(p)
		p = p[size:]
		txt.WriteRune(r)
	}

	return
}

func (txt *Text) WriteString(s string) (n int, err error) {
	if len(s) == 0 {
		return
	}

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for _, r := range s {
		txt.WriteRune(r)
	}

	return len(s), nil
}

func (txt *Text) WriteByte(c byte) error {
	_, err := txt.WriteRune(rune(c))
	return err
}

func (txt *Text) WriteRune(r rune) (n int, err error) {
	n, err = utf8.RuneLen(r), nil // always returns this

	switch r {
	case '\n':
		txt.Dot -= pixel.Y(txt.atlas.lineHeight * txt.lineHeight)
		txt.Dot = txt.Dot.WithX(txt.Orig.X())
		return
	case '\r':
		txt.Dot = txt.Dot.WithX(txt.Orig.X())
		return
	case '\t':
		//TODO: properly align tab
		txt.Dot += pixel.X(txt.tabWidth)
		return
	}

	if !txt.atlas.Contains(r) {
		r = unicode.ReplacementChar
	}
	if !txt.atlas.Contains(unicode.ReplacementChar) {
		return
	}

	glyph := txt.atlas.Glyph(r)

	if txt.prevR >= 0 {
		txt.Dot += pixel.X(txt.atlas.Kern(txt.prevR, r))
	}

	a := pixel.V(glyph.Frame.Min.X(), glyph.Frame.Min.Y())
	b := pixel.V(glyph.Frame.Max.X(), glyph.Frame.Min.Y())
	c := pixel.V(glyph.Frame.Max.X(), glyph.Frame.Max.Y())
	d := pixel.V(glyph.Frame.Min.X(), glyph.Frame.Max.Y())

	for i, v := range []pixel.Vec{a, b, c, a, c, d} {
		txt.glyph[i].Position = v - glyph.Orig + txt.Dot
		txt.glyph[i].Picture = v
	}

	txt.tris = append(txt.tris, txt.glyph...)

	txt.Dot += pixel.X(glyph.Advance)
	txt.prevR = r

	txt.d.Dirty()

	return
}

func (txt *Text) Draw(t pixel.Target) {
	txt.trans.Clear()
	txt.d.Draw(txt.trans)
	txt.trans.Draw(t)
}

type Glyph struct {
	Orig    pixel.Vec
	Frame   pixel.Rect
	Advance float64
}

type Atlas struct {
	pic        pixel.Picture
	mapping    map[rune]Glyph
	kern       map[struct{ r0, r1 rune }]float64
	lineHeight float64
}

func NewAtlas(face font.Face, runes []rune) *Atlas {
	//FIXME: don't put glyphs in just one row, make a square

	width := fixed.Int26_6(0)
	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}
		width += b.Max.X - b.Min.X

		// padding to avoid filtering artifacts
		width = fixed.I(width.Ceil())
		width += fixed.I(2)
	}

	atlasImg := image.NewRGBA(image.Rect(
		0, 0,
		width.Ceil(), (face.Metrics().Ascent + face.Metrics().Descent).Ceil(),
	))
	atlasHeight := float64(atlasImg.Bounds().Dy())

	mapping := make(map[rune]Glyph)

	dot := fixed.Point26_6{
		X: 0,
		Y: face.Metrics().Ascent,
	}

	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}

		dot.X -= b.Min.X

		dr, mask, maskp, _, _ := face.Glyph(dot, r)
		draw.Draw(atlasImg, dr, mask, maskp, draw.Src)

		orig := pixel.V(
			float64(dot.X)/(1<<6),
			atlasHeight-float64(dot.Y)/(1<<6),
		)

		frame := pixel.R(
			float64(dr.Min.X),
			atlasHeight-float64(dr.Min.Y),
			float64(dr.Max.X),
			atlasHeight-float64(dr.Max.Y),
		).Norm()

		adv, _ := face.GlyphAdvance(r)
		advance := float64(adv) / (1 << 6)

		mapping[r] = Glyph{orig, frame, advance}

		dot.X += b.Max.X

		// padding
		dot.X = fixed.I(dot.X.Ceil())
		dot.X += fixed.I(2)
	}

	kern := make(map[struct{ r0, r1 rune }]float64)
	for _, r0 := range runes {
		for _, r1 := range runes {
			kern[struct{ r0, r1 rune }{r0, r1}] = float64(face.Kern(r0, r1)) / (1 << 6)
		}
	}

	return &Atlas{
		pixel.PictureDataFromImage(atlasImg),
		mapping,
		kern,
		float64(face.Metrics().Height) / (1 << 6),
	}
}

func (a *Atlas) Picture() pixel.Picture {
	return a.pic
}

func (a *Atlas) Contains(r rune) bool {
	_, ok := a.mapping[r]
	return ok
}

func (a *Atlas) Glyph(r rune) Glyph {
	return a.mapping[r]
}

func (a *Atlas) Kern(r0, r1 rune) float64 {
	return a.kern[struct{ r0, r1 rune }{r0, r1}]
}

func (a *Atlas) LineHeight() float64 {
	return a.lineHeight
}
<commit_msg>change Text.LineHeight to use actual units instead of scale (such as 1.5)<commit_after>package text

import (
	"image"
	"image/color"
	"image/draw"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

type Text struct {
	Orig pixel.Vec
	Dot  pixel.Vec

	atlas *Atlas

	color      pixel.RGBA
	lineHeight float64
	tabWidth   float64

	prevR rune
	glyph pixel.TrianglesData
	tris  pixel.TrianglesData
	d     pixel.Drawer
	trans *pixel.Batch
}

func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	atlas := NewAtlas(face, runes)

	txt := &Text{
		atlas:      atlas,
		color:      pixel.Alpha(1),
		lineHeight: atlas.LineHeight(),
		tabWidth:   atlas.Glyph(' ').Advance * 4,
	}
	txt.glyph.SetLen(6)
	txt.d.Picture = txt.atlas.pic
	txt.d.Triangles = &txt.tris
	txt.trans = pixel.NewBatch(&pixel.TrianglesData{}, atlas.pic)

	txt.Clear()

	return txt
}

func (txt *Text) Atlas() *Atlas {
	return txt.atlas
}

func (txt *Text) SetMatrix(m pixel.Matrix) {
	txt.trans.SetMatrix(m)
}

func (txt *Text) SetColorMask(c color.Color) {
	txt.trans.SetColorMask(c)
}

func (txt *Text) Color(c color.Color) {
	txt.color = pixel.ToRGBA(c)
}

func (txt *Text) LineHeight(scale float64) {
	txt.lineHeight = scale
}

func (txt *Text) TabWidth(width float64) {
	txt.tabWidth = width
}

func (txt *Text) Clear() {
	txt.prevR = -1
	txt.tris.SetLen(0)
	txt.d.Dirty()
}

func (txt *Text) Write(p []byte) (n int, err error) {
	n, err = len(p), nil // always returns this

	if len(p) == 0 {
		return
	}

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for len(p) > 0 {
		r, size := utf8.DecodeRune(p)
		p = p[size:]
		txt.WriteRune(r)
	}

	return
}

func (txt *Text) WriteString(s string) (n int, err error) {
	if len(s) == 0 {
		return
	}

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for _, r := range s {
		txt.WriteRune(r)
	}

	return len(s), nil
}

func (txt *Text) WriteByte(c byte) error {
	_, err := txt.WriteRune(rune(c))
	return err
}

func (txt *Text) WriteRune(r rune) (n int, err error) {
	n, err = utf8.RuneLen(r), nil // always returns this

	switch r {
	case '\n':
		txt.Dot -= pixel.Y(txt.lineHeight)
		txt.Dot = txt.Dot.WithX(txt.Orig.X())
		return
	case '\r':
		txt.Dot = txt.Dot.WithX(txt.Orig.X())
		return
	case '\t':
		//TODO: properly align tab
		txt.Dot += pixel.X(txt.tabWidth)
		return
	}

	if !txt.atlas.Contains(r) {
		r = unicode.ReplacementChar
	}
	if !txt.atlas.Contains(unicode.ReplacementChar) {
		return
	}

	glyph := txt.atlas.Glyph(r)

	if txt.prevR >= 0 {
		txt.Dot += pixel.X(txt.atlas.Kern(txt.prevR, r))
	}

	a := pixel.V(glyph.Frame.Min.X(), glyph.Frame.Min.Y())
	b := pixel.V(glyph.Frame.Max.X(), glyph.Frame.Min.Y())
	c := pixel.V(glyph.Frame.Max.X(), glyph.Frame.Max.Y())
	d := pixel.V(glyph.Frame.Min.X(), glyph.Frame.Max.Y())

	for i, v := range []pixel.Vec{a, b, c, a, c, d} {
		txt.glyph[i].Position = v - glyph.Orig + txt.Dot
		txt.glyph[i].Picture = v
	}

	txt.tris = append(txt.tris, txt.glyph...)

	txt.Dot += pixel.X(glyph.Advance)
	txt.prevR = r

	txt.d.Dirty()

	return
}

func (txt *Text) Draw(t pixel.Target) {
	txt.trans.Clear()
	txt.d.Draw(txt.trans)
	txt.trans.Draw(t)
}

type Glyph struct {
	Orig    pixel.Vec
	Frame   pixel.Rect
	Advance float64
}

type Atlas struct {
	pic        pixel.Picture
	mapping    map[rune]Glyph
	kern       map[struct{ r0, r1 rune }]float64
	lineHeight float64
}

func NewAtlas(face font.Face, runes []rune) *Atlas {
	//FIXME: don't put glyphs in just one row, make a square

	width := fixed.Int26_6(0)
	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}
		width += b.Max.X - b.Min.X

		// padding to avoid filtering artifacts
		width = fixed.I(width.Ceil())
		width += fixed.I(2)
	}

	atlasImg := image.NewRGBA(image.Rect(
		0, 0,
		width.Ceil(), (face.Metrics().Ascent + face.Metrics().Descent).Ceil(),
	))
	atlasHeight := float64(atlasImg.Bounds().Dy())

	mapping := make(map[rune]Glyph)

	dot := fixed.Point26_6{
		X: 0,
		Y: face.Metrics().Ascent,
	}

	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}

		dot.X -= b.Min.X

		dr, mask, maskp, _, _ := face.Glyph(dot, r)
		draw.Draw(atlasImg, dr, mask, maskp, draw.Src)

		orig := pixel.V(
			float64(dot.X)/(1<<6),
			atlasHeight-float64(dot.Y)/(1<<6),
		)

		frame := pixel.R(
			float64(dr.Min.X),
			atlasHeight-float64(dr.Min.Y),
			float64(dr.Max.X),
			atlasHeight-float64(dr.Max.Y),
		).Norm()

		adv, _ := face.GlyphAdvance(r)
		advance := float64(adv) / (1 << 6)

		mapping[r] = Glyph{orig, frame, advance}

		dot.X += b.Max.X

		// padding
		dot.X = fixed.I(dot.X.Ceil())
		dot.X += fixed.I(2)
	}

	kern := make(map[struct{ r0, r1 rune }]float64)
	for _, r0 := range runes {
		for _, r1 := range runes {
			kern[struct{ r0, r1 rune }{r0, r1}] = float64(face.Kern(r0, r1)) / (1 << 6)
		}
	}

	return &Atlas{
		pixel.PictureDataFromImage(atlasImg),
		mapping,
		kern,
		float64(face.Metrics().Height) / (1 << 6),
	}
}

func (a *Atlas) Picture() pixel.Picture {
	return a.pic
}

func (a *Atlas) Contains(r rune) bool {
	_, ok := a.mapping[r]
	return ok
}

func (a *Atlas) Glyph(r rune) Glyph {
	return a.mapping[r]
}

func (a *Atlas) Kern(r0, r1 rune) float64 {
	return a.kern[struct{ r0, r1 rune }{r0, r1}]
}

func (a *Atlas) LineHeight() float64 {
	return a.lineHeight
}
<|endoftext|>


<commit_before>package availability_test

import (
	"net"
	"time"

	"github.com/pivotal-cf/cf-redis-broker/availability"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func listen(address net.TCPAddr, delayBeforeListening time.Duration, terminate, closed chan struct{}) {
	listener, err := net.ListenTCP("tcp", &address)
	Ω(err).ShouldNot(HaveOccurred())
	go func() {
		select {
		case <-terminate:
			listener.Close()
			close(closed)
		}
	}()
	time.Sleep(delayBeforeListening)
	listener.AcceptTCP()
}

var _ = Describe("waiting for a port to become available", func() {

	var address *net.TCPAddr

	BeforeEach(func() {
		var err error
		address, err = net.ResolveTCPAddr("tcp", "localhost:19000")
		Ω(err).ShouldNot(HaveOccurred())
	})

	Context("when nothing is listening at the specified address", func() {
		It("errors", func() {
			err := availability.Check(address, time.Second*1)
			Ω(err).Should(HaveOccurred())
		})
	})

	Context("when something is already listening at the specified address", func() {
		terminate := make(chan struct{})
		closed := make(chan struct{})

		BeforeEach(func() {
			go func() {
				defer GinkgoRecover()
				listen(*address, 0, terminate, closed)
			}()
		})

		AfterEach(func() {
			close(terminate)
			Eventually(closed).Should(BeClosed())
		})

		It("does not error", func() {
			err := availability.Check(address, time.Second*1)
			Ω(err).ShouldNot(HaveOccurred())
		})
	})

	Context("when something begins to listen on address before timeout is up", func() {
		terminate := make(chan struct{})
		closed := make(chan struct{})

		BeforeEach(func() {
			go func() {
				defer GinkgoRecover()

				listen(*address, 500*time.Millisecond, terminate, closed)
			}()
		})

		AfterEach(func() {
			close(terminate)
			Eventually(closed).Should(BeClosed())
		})

		It("does not error", func() {
			err := availability.Check(address, time.Second*1)
			Ω(err).ShouldNot(HaveOccurred())
		})
	})
})
<commit_msg>use consistent test language<commit_after>package availability_test

import (
	"net"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pivotal-cf/cf-redis-broker/availability"
)

func listen(address net.TCPAddr, delayBeforeListening time.Duration, terminate, closed chan struct{}) {
	listener, err := net.ListenTCP("tcp", &address)
	Expect(err).NotTo(HaveOccurred())
	go func() {
		select {
		case <-terminate:
			listener.Close()
			close(closed)
		}
	}()
	time.Sleep(delayBeforeListening)
	listener.AcceptTCP()
}

var _ = Describe("waiting for a port to become available", func() {
	var address *net.TCPAddr

	BeforeEach(func() {
		var err error
		address, err = net.ResolveTCPAddr("tcp", "localhost:19000")
		Expect(err).NotTo(HaveOccurred())
	})

	Context("when nothing is listening at the specified address", func() {
		It("errors", func() {
			err := availability.Check(address, time.Second*1)
			Expect(err).To(HaveOccurred())
		})
	})

	Context("when something is already listening at the specified address", func() {
		terminate := make(chan struct{})
		closed := make(chan struct{})

		BeforeEach(func() {
			go func() {
				defer GinkgoRecover()
				listen(*address, 0, terminate, closed)
			}()
		})

		AfterEach(func() {
			close(terminate)
			Eventually(closed).Should(BeClosed())
		})

		It("does not error", func() {
			err := availability.Check(address, time.Second*1)
			Expect(err).NotTo(HaveOccurred())
		})
	})

	Context("when something begins to listen on address before timeout is up", func() {
		terminate := make(chan struct{})
		closed := make(chan struct{})

		BeforeEach(func() {
			go func() {
				defer GinkgoRecover()

				listen(*address, 500*time.Millisecond, terminate, closed)
			}()
		})

		AfterEach(func() {
			close(terminate)
			Eventually(closed).Should(BeClosed())
		})

		It("does not error", func() {
			err := availability.Check(address, time.Second*1)
			Expect(err).NotTo(HaveOccurred())
		})
	})
})
<|endoftext|>


<commit_before>// In this example HTTP traffic is inspected by introspecting on an underlying
// TCP acceptor. By injecting callbacks on Accept, Read, Write and Close we can
// track stats for each individual connection as it changes state.
//
// This is only one possible use case of the connxray library.
package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/golang/glog"
	xray "github.com/marcinwyszynski/connxray"
)

var (
	port = flag.Int("port", 1983, "HTTP port")
)

type ReadCallback func(*xray.Conn, []byte, int, error)
type WriteCallback func(*xray.Conn, []byte, int, error)
type CloseCallback func(*xray.Conn, error)

type stats struct {
	bytesRead    int
	bytesWritten int
	startTime    time.Time
}

func onAccept(_ *xray.Listener, conn *xray.Conn, err error) {
	s := &stats{startTime: time.Now()}
	conn.AfterRead = onRead(s)
	conn.AfterWrite = onWrite(s)
	conn.AfterClose = onClose(s)
	if err != nil {
		glog.Errorf("Error establishing connection: %v", err)
		return
	}
	glog.Infof("%s <-> %s started", conn.LocalAddr(), conn.RemoteAddr())
}

func onRead(s *stats) ReadCallback {
	return func(conn *xray.Conn, _ []byte, n int, err error) {
		s.bytesRead += n
		if err == nil {
			return
		}
		if err == io.EOF {
			msg := "Finished reading from connection with %s"
			glog.Errorf(msg, conn.RemoteAddr())
			return
		}
		msg := "Error reading from connection with %s: %v"
		glog.Errorf(msg, conn.RemoteAddr(), err)
	}
}

func onWrite(s *stats) WriteCallback {
	return func(conn *xray.Conn, _ []byte, n int, err error) {
		s.bytesWritten += n
		if err == nil {
			return
		}
		msg := "Error writing to connection with %s: %v"
		glog.Errorf(msg, conn.RemoteAddr(), err)
	}
}

func onClose(s *stats) CloseCallback {
	return func(conn *xray.Conn, err error) {
		if err != nil {
			msg := "Error closing connection with %s: %v"
			glog.Errorf(msg, conn.RemoteAddr(), err)
		}
		msg := "%s closed: %d bytes read, %d bytes written in %d ms"
		glog.Infof(
			msg,
			conn.RemoteAddr(),
			s.bytesRead,
			s.bytesWritten,
			time.Since(s.startTime)/1e6,
		)
	}
}

func main() {
	flag.Parse()
	addr := net.TCPAddr{Port: *port}
	tcpLisetner, err := net.ListenTCP("tcp", &addr)
	if err != nil {
		glog.Fatalf("Error creating a TCP listener: %v", err)
	}
	introspectedListener := &xray.Listener{
		Base:        tcpLisetner,
		AfterAccept: onAccept,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello world!")
	})
	glog.Infof("About to start serving on %s", addr.String())
	glog.Fatal(http.Serve(introspectedListener, nil))
}
<commit_msg>simplify example<commit_after>// In this example HTTP traffic is inspected by introspecting on an underlying
// TCP acceptor. By injecting callbacks on Accept, Read, Write and Close we can
// track stats for each individual connection as it changes state.
//
// This is only one possible use case of the connxray library.
package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"time"

	"github.com/golang/glog"
	xray "github.com/marcinwyszynski/connxray"
)

var (
	port = flag.Int("port", 1983, "HTTP port")
)

type ReadCallback func(*xray.Conn, []byte, int, error)
type WriteCallback func(*xray.Conn, []byte, int, error)
type CloseCallback func(*xray.Conn, error)

type stats struct {
	bytesRead    int
	bytesWritten int
	startTime    time.Time
}

func onAccept(_ *xray.Listener, conn *xray.Conn, err error) {
	s := &stats{startTime: time.Now()}
	conn.AfterRead = onRead(s)
	conn.AfterWrite = onWrite(s)
	conn.AfterClose = onClose(s)
	if err != nil {
		glog.Errorf("Error establishing connection: %v", err)
		return
	}
	glog.Infof("%s <-> %s started", conn.LocalAddr(), conn.RemoteAddr())
}

func onRead(s *stats) ReadCallback {
	return func(_ *xray.Conn, _ []byte, n int, _ error) {
		s.bytesRead += n
	}
}

func onWrite(s *stats) WriteCallback {
	return func(_ *xray.Conn, _ []byte, n int, _ error) {
		s.bytesWritten += n
	}
}

func onClose(s *stats) CloseCallback {
	return func(conn *xray.Conn, _ error) {
		msg := "%s closed: %d bytes read, %d bytes written in %d ms"
		glog.Infof(
			msg,
			conn.RemoteAddr(),
			s.bytesRead,
			s.bytesWritten,
			time.Since(s.startTime)/1e6,
		)
	}
}

func main() {
	flag.Parse()
	addr := net.TCPAddr{Port: *port}
	tcpLisetner, err := net.ListenTCP("tcp", &addr)
	if err != nil {
		glog.Fatalf("Error creating a TCP listener: %v", err)
	}
	introspectedListener := &xray.Listener{
		Base:        tcpLisetner,
		AfterAccept: onAccept,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello world!")
	})
	glog.Infof("About to start serving on %s", addr.String())
	glog.Fatal(http.Serve(introspectedListener, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"net/http"
	"sync"
	"time"

	clusterConfig "github.com/lxc/lxd/lxd/cluster/config"
	"github.com/lxc/lxd/lxd/db"
	dbCluster "github.com/lxc/lxd/lxd/db/cluster"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/metrics"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared/logger"
)

type metricsCacheEntry struct {
	metrics *metrics.MetricSet
	expiry  time.Time
}

var metricsCache map[string]metricsCacheEntry
var metricsCacheLock sync.Mutex
var metricsLock sync.Mutex

var metricsCmd = APIEndpoint{
	Path: "metrics",

	Get: APIEndpointAction{Handler: metricsGet, AccessHandler: allowMetrics, AllowUntrusted: true},
}

func allowMetrics(d *Daemon, r *http.Request) response.Response {
	// Check if API is wide open.
	isAuthenticated, err := clusterConfig.GetBool(d.db.Cluster, "core.metrics_authentication")
	if err != nil {
		return response.InternalError(err)
	}

	if !isAuthenticated {
		return response.EmptySyncResponse
	}

	// If not wide open, apply project access restrictions.
	return allowProjectPermission("containers", "view")(d, r)
}

// swagger:operation GET /1.0/metrics metrics metrics_get
//
// Get metrics
//
// Gets metrics of instances.
//
// ---
// produces:
//   - text/plain
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: query
//     name: target
//     description: Cluster member name
//     type: string
//     example: lxd01
// responses:
//   "200":
//     description: Metrics
//     schema:
//       type: string
//       description: Instance metrics
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func metricsGet(d *Daemon, r *http.Request) response.Response {
	projectName := queryParam(r, "project")

	// Forward if requested.
	resp := forwardedResponseIfTargetIsRemote(d, r)
	if resp != nil {
		return resp
	}

	// Figure out the projects to retrieve.
	var projectNames []string

	if projectName != "" {
		projectNames = []string{projectName}
	} else {
		// Get all projects.
		err := d.db.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
			projects, err := dbCluster.GetProjects(ctx, tx.Tx(), dbCluster.ProjectFilter{})
			if err != nil {
				return err
			}

			for _, project := range projects {
				projectNames = append(projectNames, project.Name)
			}

			return nil
		})
		if err != nil {
			return response.SmartError(err)
		}
	}

	// Prepare response.
	metricSet := metrics.NewMetricSet(nil)

	// Review the cache.
	metricsCacheLock.Lock()
	projectMissing := []string{}
	for _, project := range projectNames {
		cache, ok := metricsCache[project]
		if !ok || cache.expiry.Before(time.Now()) {
			// If missing or expired, record it.
			projectMissing = append(projectMissing, project)
			continue
		}

		// If present and valid, merge the existing data.
		metricSet.Merge(cache.metrics)
	}
	metricsCacheLock.Unlock()

	// If all valid, return immediately.
	if len(projectMissing) == 0 {
		return response.SyncResponsePlain(true, metricSet.String())
	}

	// Acquire update lock.
	metricsLock.Lock()
	defer metricsLock.Unlock()

	// Check if any of the missing data has been filled in.
	metricsCacheLock.Lock()
	toFetch := []string{}
	for _, project := range projectMissing {
		cache, ok := metricsCache[project]
		if !ok || cache.expiry.Before(time.Now()) {
			// Still missing, queue a re-fetch.
			toFetch = append(toFetch, project)
			continue
		}

		// If present and valid, merge the existing data.
		metricSet.Merge(cache.metrics)
	}
	metricsCacheLock.Unlock()

	// If all valid, return immediately.
	if len(toFetch) == 0 {
		return response.SyncResponsePlain(true, metricSet.String())
	}

	// Prepare temporary metrics storage.
	newMetrics := map[string]*metrics.MetricSet{}
	newMetricsLock := sync.Mutex{}

	// Fetch what's missing.
	wgInstances := sync.WaitGroup{}
	for _, project := range toFetch {
		newMetrics[project] = metrics.NewMetricSet(nil)

		// Get the instances.
		instances, err := instanceLoadNodeProjectAll(d.State(), project, instancetype.Any)
		if err != nil {
			return response.SmartError(err)
		}

		for _, inst := range instances {
			// Ignore stopped instances.
			if !inst.IsRunning() {
				continue
			}

			wgInstances.Add(1)
			go func(inst instance.Instance) {
				defer wgInstances.Done()

				instanceMetrics, err := inst.Metrics()
				if err != nil {
					logger.Warn("Failed to get instance metrics", logger.Ctx{"instance": inst.Name(), "project": inst.Project(), "err": err})
					return
				}

				// Add the metrics.
				newMetricsLock.Lock()
				defer newMetricsLock.Unlock()

				newMetrics[inst.Project()].Merge(instanceMetrics)
			}(inst)
		}
	}

	wgInstances.Wait()

	// Put the new data in the global cache and in response.
	metricsCacheLock.Lock()

	if metricsCache == nil {
		metricsCache = map[string]metricsCacheEntry{}
	}

	for project, entries := range newMetrics {
		metricsCache[project] = metricsCacheEntry{
			expiry:  time.Now().Add(8 * time.Second),
			metrics: entries,
		}

		metricSet.Merge(entries)
	}
	metricsCacheLock.Unlock()

	return response.SyncResponsePlain(true, metricSet.String())
}
<commit_msg>lxd/api_metrics: Avoid needless DB calls<commit_after>package main

import (
	"context"
	"net/http"
	"sync"
	"time"

	"github.com/lxc/lxd/lxd/db"
	dbCluster "github.com/lxc/lxd/lxd/db/cluster"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/metrics"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared/logger"
)

type metricsCacheEntry struct {
	metrics *metrics.MetricSet
	expiry  time.Time
}

var metricsCache map[string]metricsCacheEntry
var metricsCacheLock sync.Mutex
var metricsLock sync.Mutex

var metricsCmd = APIEndpoint{
	Path: "metrics",

	Get: APIEndpointAction{Handler: metricsGet, AccessHandler: allowMetrics, AllowUntrusted: true},
}

func allowMetrics(d *Daemon, r *http.Request) response.Response {
	// Check if API is wide open.
	if !d.State().GlobalConfig.MetricsAuthentication() {
		return response.EmptySyncResponse
	}

	// If not wide open, apply project access restrictions.
	return allowProjectPermission("containers", "view")(d, r)
}

// swagger:operation GET /1.0/metrics metrics metrics_get
//
// Get metrics
//
// Gets metrics of instances.
//
// ---
// produces:
//   - text/plain
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: query
//     name: target
//     description: Cluster member name
//     type: string
//     example: lxd01
// responses:
//   "200":
//     description: Metrics
//     schema:
//       type: string
//       description: Instance metrics
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func metricsGet(d *Daemon, r *http.Request) response.Response {
	projectName := queryParam(r, "project")

	// Forward if requested.
	resp := forwardedResponseIfTargetIsRemote(d, r)
	if resp != nil {
		return resp
	}

	// Figure out the projects to retrieve.
	var projectNames []string

	if projectName != "" {
		projectNames = []string{projectName}
	} else {
		// Get all projects.
		err := d.db.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
			projects, err := dbCluster.GetProjects(ctx, tx.Tx(), dbCluster.ProjectFilter{})
			if err != nil {
				return err
			}

			for _, project := range projects {
				projectNames = append(projectNames, project.Name)
			}

			return nil
		})
		if err != nil {
			return response.SmartError(err)
		}
	}

	// Prepare response.
	metricSet := metrics.NewMetricSet(nil)

	// Review the cache.
	metricsCacheLock.Lock()
	projectMissing := []string{}
	for _, project := range projectNames {
		cache, ok := metricsCache[project]
		if !ok || cache.expiry.Before(time.Now()) {
			// If missing or expired, record it.
			projectMissing = append(projectMissing, project)
			continue
		}

		// If present and valid, merge the existing data.
		metricSet.Merge(cache.metrics)
	}
	metricsCacheLock.Unlock()

	// If all valid, return immediately.
	if len(projectMissing) == 0 {
		return response.SyncResponsePlain(true, metricSet.String())
	}

	// Acquire update lock.
	metricsLock.Lock()
	defer metricsLock.Unlock()

	// Check if any of the missing data has been filled in.
	metricsCacheLock.Lock()
	toFetch := []string{}
	for _, project := range projectMissing {
		cache, ok := metricsCache[project]
		if !ok || cache.expiry.Before(time.Now()) {
			// Still missing, queue a re-fetch.
			toFetch = append(toFetch, project)
			continue
		}

		// If present and valid, merge the existing data.
		metricSet.Merge(cache.metrics)
	}
	metricsCacheLock.Unlock()

	// If all valid, return immediately.
	if len(toFetch) == 0 {
		return response.SyncResponsePlain(true, metricSet.String())
	}

	// Prepare temporary metrics storage.
	newMetrics := map[string]*metrics.MetricSet{}
	newMetricsLock := sync.Mutex{}

	// Fetch what's missing.
	wgInstances := sync.WaitGroup{}
	for _, project := range toFetch {
		newMetrics[project] = metrics.NewMetricSet(nil)

		// Get the instances.
		instances, err := instanceLoadNodeProjectAll(d.State(), project, instancetype.Any)
		if err != nil {
			return response.SmartError(err)
		}

		for _, inst := range instances {
			// Ignore stopped instances.
			if !inst.IsRunning() {
				continue
			}

			wgInstances.Add(1)
			go func(inst instance.Instance) {
				defer wgInstances.Done()

				instanceMetrics, err := inst.Metrics()
				if err != nil {
					logger.Warn("Failed to get instance metrics", logger.Ctx{"instance": inst.Name(), "project": inst.Project(), "err": err})
					return
				}

				// Add the metrics.
				newMetricsLock.Lock()
				defer newMetricsLock.Unlock()

				newMetrics[inst.Project()].Merge(instanceMetrics)
			}(inst)
		}
	}

	wgInstances.Wait()

	// Put the new data in the global cache and in response.
	metricsCacheLock.Lock()

	if metricsCache == nil {
		metricsCache = map[string]metricsCacheEntry{}
	}

	for project, entries := range newMetrics {
		metricsCache[project] = metricsCacheEntry{
			expiry:  time.Now().Add(8 * time.Second),
			metrics: entries,
		}

		metricSet.Merge(entries)
	}
	metricsCacheLock.Unlock()

	return response.SyncResponsePlain(true, metricSet.String())
}
<|endoftext|>


<commit_before>package lzbase

import (
	"fmt"
	"io"
	"unicode"
)

// operation represents an operation on the dictionary during encoding or
// decoding.
type Operation interface {
	Len() int
}

// rep represents a repetition at the given distance and the given length
type match struct {
	// supports all possible distance values, including the eos marker
	distance int64
	length   int
}

// eos is a special kind of match.
var eos = match{distance: maxDistance, length: MinLength}

// EOS may mark the end of an LZMA stream.
var EOS = Operation(eos)

// Len return the length of the repetition.
func (m match) Len() int {
	return m.length
}

// String returns a string representation for the repetition.
func (m match) String() string {
	return fmt.Sprintf("match{%d,%d}", m.distance, m.length)
}

// lit represents a single byte literal.
type lit struct {
	b byte
}

// Len returns 1 for the single byte literal.
func (l lit) Len() int {
	return 1
}

// String returns a string representation for the literal.
func (l lit) String() string {
	var c byte
	if unicode.IsPrint(rune(l.b)) {
		c = l.b
	} else {
		c = '.'
	}
	return fmt.Sprintf("lit{%02x %c}", l.b, c)
}

// OpEncoder translates a sequences of operations to a byte stream.
type OpEncoder struct {
	W     io.Writer
	State *State
	re    *rangeEncoder
}

// NewOpEncoder creates a new OpEncoder value. Writer and state cannot be
// shared with other instances.
func NewOpEncoder(w io.Writer, state *State) (e *OpEncoder, err error) {
	switch {
	case w == nil:
		return nil, newError("NewOpEncoder argument w is nil")
	case state == nil:
		return nil, newError("NewOpEncoder argument state is nil")
	}
	e = &OpEncoder{
		W:     w,
		State: state,
		re:    newRangeEncoder(w),
	}
	return e, nil
}

// iverson translates a boolean into an integer value. Donald Knuth calls a
// mathematical operator doing the same Iverson operator in Concrete
// Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a match operation into the range encoder.
func (e *OpEncoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return newError("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.length && m.length <= MaxLength) &&
		!(dist == e.State.rep[0] && m.length == 1) {
		return newError("length out of range")
	}
	state, state2, posState := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.length - MinLength)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] = e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.length != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeLiteral writes a literal into the operation stream
func (e *OpEncoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState()
	match := e.State.dict.Byte(int64(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// WriteOps translates the given operations into an encoded byte stream. The
// number of operations written will be reported and any error condition. Note
// that an error might indicate that parts of the operation have already been
// written.
func (e *OpEncoder) WriteOps(ops []Operation) (n int, err error) {
	for _, op := range ops {
		switch x := op.(type) {
		case match:
			if err = e.writeMatch(x); err != nil {
				return n, err
			}
		case lit:
			if err = e.writeLiteral(x); err != nil {
				return n, err
			}
		default:
			return n, newError("unknown operation type")
		}
		n++
	}
	return n, nil
}

// Close closes the encoder.
func (e *OpEncoder) Close() error {
	return e.re.Close()
}
<commit_msg>lzbase: skeleton for OpDecoder has been implemented<commit_after>package lzbase

import (
	"fmt"
	"io"
	"unicode"
)

// operation represents an operation on the dictionary during encoding or
// decoding.
type Operation interface {
	Len() int
}

// rep represents a repetition at the given distance and the given length
type match struct {
	// supports all possible distance values, including the eos marker
	distance int64
	length   int
}

// eos is a special kind of match.
var eos = match{distance: maxDistance, length: MinLength}

// EOS may mark the end of an LZMA stream.
var EOS = Operation(eos)

// Len return the length of the repetition.
func (m match) Len() int {
	return m.length
}

// String returns a string representation for the repetition.
func (m match) String() string {
	return fmt.Sprintf("match{%d,%d}", m.distance, m.length)
}

// lit represents a single byte literal.
type lit struct {
	b byte
}

// Len returns 1 for the single byte literal.
func (l lit) Len() int {
	return 1
}

// String returns a string representation for the literal.
func (l lit) String() string {
	var c byte
	if unicode.IsPrint(rune(l.b)) {
		c = l.b
	} else {
		c = '.'
	}
	return fmt.Sprintf("lit{%02x %c}", l.b, c)
}

// OpEncoder translates a sequences of operations to a byte stream.
type OpEncoder struct {
	W     io.Writer
	State *State
	re    *rangeEncoder
}

// NewOpEncoder creates a new OpEncoder value. Writer and state cannot be
// shared with other instances.
func NewOpEncoder(w io.Writer, state *State) (e *OpEncoder, err error) {
	switch {
	case w == nil:
		return nil, newError("NewOpEncoder argument w is nil")
	case state == nil:
		return nil, newError("NewOpEncoder argument state is nil")
	}
	e = &OpEncoder{
		W:     w,
		State: state,
		re:    newRangeEncoder(w),
	}
	return e, nil
}

// iverson translates a boolean into an integer value. Donald Knuth calls a
// mathematical operator doing the same Iverson operator in Concrete
// Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a match operation into the range encoder.
func (e *OpEncoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return newError("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.length && m.length <= MaxLength) &&
		!(dist == e.State.rep[0] && m.length == 1) {
		return newError("length out of range")
	}
	state, state2, posState := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.length - MinLength)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] = e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.length != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeLiteral writes a literal into the operation stream
func (e *OpEncoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState()
	match := e.State.dict.Byte(int64(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// WriteOps translates the given operations into an encoded byte stream. The
// number of operations written will be reported and any error condition. Note
// that an error might indicate that parts of the operation have already been
// written.
func (e *OpEncoder) WriteOps(ops []Operation) (n int, err error) {
	for _, op := range ops {
		switch x := op.(type) {
		case match:
			if err = e.writeMatch(x); err != nil {
				return n, err
			}
		case lit:
			if err = e.writeLiteral(x); err != nil {
				return n, err
			}
		default:
			return n, newError("unknown operation type")
		}
		n++
	}
	return n, nil
}

// Close closes the encoder.
func (e *OpEncoder) Close() error {
	return e.re.Close()
}

// OpDecoder translates a byte stream to a sequence of operations.
type OpDecoder struct {
	R     io.Reader
	State *State
	rd    *rangeDecoder
}

// NewOpDecoder creates a new OpDecoder valure. Reader and state cannot be
// shared with other instances.
func NewOpDecoder(r io.Reader, state *State) (d *OpDecoder, err error) {
	panic("TODO")
}

// ReadOps reads a sequence of operations. The number of operations read will
// be returned. Note that an error may indicate that the read of a full
// operation has not been successful.
func (d *OpDecoder) ReadOps(ops []Operation) (n int, err error) {
	panic("TODO")
}
<|endoftext|>