Remove (Mutable)ArraySlice implementation and alias them to absl::Span.
There are several API migrations happening: * ArraySlice's sub-slice constructor => .subspan * MutableArraySlice's container pointer constructor => absl::MakeSpan PiperOrigin-RevId: 210946124
This commit is contained in:
parent
9e12f1df32
commit
09f2c342c0
tensorflow
compiler
tests
tf2xla/lib
xla
core
stream_executor/cuda
@ -1884,7 +1884,8 @@ TEST_F(OpTest, DynamicStitch) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
TensorShape shape(index_dims[i]);
|
||||
Tensor t = test::AsTensor<int32>(
|
||||
gtl::ArraySlice<int32>(indices, pos, shape.num_elements()), shape);
|
||||
gtl::ArraySlice<int32>(indices).subspan(pos, shape.num_elements()),
|
||||
shape);
|
||||
builder.Input(t);
|
||||
pos += t.NumElements();
|
||||
}
|
||||
|
@ -56,9 +56,10 @@ xla::XlaOp CholeskyUnblocked(xla::XlaOp a,
|
||||
TF_ASSIGN_OR_RETURN(xla::Shape a_shape, builder->GetShape(a));
|
||||
const int n_dims = xla::ShapeUtil::Rank(a_shape);
|
||||
const int64 n = xla::ShapeUtil::GetDimension(a_shape, -1);
|
||||
gtl::ArraySlice<int64> major_dims(xla::AsInt64Slice(a_shape.dimensions()),
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - 2);
|
||||
auto major_dims = xla::AsInt64Slice(a_shape.dimensions())
|
||||
.subspan(
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - 2);
|
||||
|
||||
xla::XlaOp l = xla::ZerosLike(a);
|
||||
|
||||
|
@ -124,9 +124,10 @@ xla::XlaOp SliceInMinorDims(xla::XlaOp x, gtl::ArraySlice<int64> start,
|
||||
|
||||
const int64 n_dims = xla::ShapeUtil::Rank(shape);
|
||||
TF_RET_CHECK(n_minor_dims <= n_dims);
|
||||
gtl::ArraySlice<int64> major_dims(xla::AsInt64Slice(shape.dimensions()),
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - n_minor_dims);
|
||||
auto major_dims = xla::AsInt64Slice(shape.dimensions())
|
||||
.subspan(
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - n_minor_dims);
|
||||
|
||||
// Prepends 0s in the major dim
|
||||
std::vector<int64> padded_start(n_dims, 0);
|
||||
@ -161,9 +162,10 @@ xla::XlaOp DynamicSliceInMinorDims(xla::XlaOp x,
|
||||
int64 n_minor_dims = starts.size();
|
||||
TF_RET_CHECK(n_minor_dims == sizes.size());
|
||||
TF_RET_CHECK(n_minor_dims <= n_dims);
|
||||
gtl::ArraySlice<int64> major_dims(xla::AsInt64Slice(shape.dimensions()),
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - sizes.size());
|
||||
auto major_dims = xla::AsInt64Slice(shape.dimensions())
|
||||
.subspan(
|
||||
/*pos=*/0,
|
||||
/*len=*/n_dims - sizes.size());
|
||||
auto padded_starts = PrependZerosInMajorDims(x, starts);
|
||||
auto padded_sizes = ConcatVectors(major_dims, sizes);
|
||||
return xla::DynamicSlice(x, padded_starts, padded_sizes);
|
||||
|
@ -39,8 +39,8 @@ XlaOp GetMatrixDiagonal(XlaOp x) {
|
||||
TF_RET_CHECK(n_dims >= 2);
|
||||
const int64 m = shape.dimensions(n_dims - 2);
|
||||
const int64 n = shape.dimensions(n_dims - 1);
|
||||
tensorflow::gtl::ArraySlice<int64> major_dims(
|
||||
AsInt64Slice(shape.dimensions()), /*pos=*/0, /*len=*/n_dims - 2);
|
||||
tensorflow::gtl::ArraySlice<int64> major_dims =
|
||||
AsInt64Slice(shape.dimensions()).subspan(/*pos=*/0, /*len=*/n_dims - 2);
|
||||
auto a = Iota(builder, U32, n);
|
||||
auto b = Iota(builder, U32, m);
|
||||
auto indicator = Eq(b, Broadcast(a, {m}), /*broadcast_dimensions=*/{0});
|
||||
@ -66,8 +66,8 @@ XlaOp Triangle(XlaOp x, bool lower) {
|
||||
TF_RET_CHECK(n_dims >= 2);
|
||||
const int64 m = shape.dimensions(n_dims - 2);
|
||||
const int64 n = shape.dimensions(n_dims - 1);
|
||||
tensorflow::gtl::ArraySlice<int64> major_dims(
|
||||
AsInt64Slice(shape.dimensions()), /*pos=*/0, /*len=*/n_dims - 2);
|
||||
tensorflow::gtl::ArraySlice<int64> major_dims =
|
||||
AsInt64Slice(shape.dimensions()).subspan(/*pos=*/0, /*len=*/n_dims - 2);
|
||||
auto a = Iota(builder, U32, n);
|
||||
auto b = Iota(builder, U32, m);
|
||||
xla::XlaOp indicator;
|
||||
|
@ -142,13 +142,13 @@ TEST(IndexUtilTest, LinearToMultiToLinear) {
|
||||
TEST(IndexUtilTest, BumpIndices2x2) {
|
||||
auto shape = ShapeUtil::MakeShape(S32, {2, 2});
|
||||
std::vector<int64> indices = {0, 0};
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, &indices));
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, absl::MakeSpan(indices)));
|
||||
EXPECT_THAT(indices, ::testing::ElementsAre(0, 1));
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, &indices));
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, absl::MakeSpan(indices)));
|
||||
EXPECT_THAT(indices, ::testing::ElementsAre(1, 0));
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, &indices));
|
||||
EXPECT_TRUE(IndexUtil::BumpIndices(shape, absl::MakeSpan(indices)));
|
||||
EXPECT_THAT(indices, ::testing::ElementsAre(1, 1));
|
||||
EXPECT_FALSE(IndexUtil::BumpIndices(shape, &indices));
|
||||
EXPECT_FALSE(IndexUtil::BumpIndices(shape, absl::MakeSpan(indices)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -366,7 +366,7 @@ void CopyElementsBetween(tensorflow::gtl::MutableArraySlice<NativeT> dest,
|
||||
do {
|
||||
dest[IndexUtil::MultidimensionalIndexToLinearIndex(dest_shape, index)] =
|
||||
src[IndexUtil::MultidimensionalIndexToLinearIndex(src_shape, index)];
|
||||
} while (IndexUtil::BumpIndices(dest_shape, &index));
|
||||
} while (IndexUtil::BumpIndices(dest_shape, absl::MakeSpan(index)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -1192,7 +1192,7 @@ void LiteralBase::EachCellAsString(
|
||||
shape(), /*linear_index=*/0);
|
||||
do {
|
||||
per_cell(indices, GetAsString(indices));
|
||||
} while (IndexUtil::BumpIndices(shape(), &indices));
|
||||
} while (IndexUtil::BumpIndices(shape(), absl::MakeSpan(indices)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1392,7 +1392,7 @@ StatusOr<std::unique_ptr<Literal>> LiteralBase::ConvertToShape(
|
||||
elements.push_back(std::move(*new_element));
|
||||
}
|
||||
auto converted = absl::make_unique<Literal>();
|
||||
*converted = MutableLiteralBase::MoveIntoTuple(&elements);
|
||||
*converted = MutableLiteralBase::MoveIntoTuple(absl::MakeSpan(elements));
|
||||
return std::move(converted);
|
||||
}
|
||||
|
||||
|
@ -992,7 +992,7 @@ void LiteralBase::EachCell(
|
||||
std::vector<int64> indices(ShapeUtil::Rank(shape()), 0);
|
||||
do {
|
||||
per_cell(indices, Get<NativeT>(indices));
|
||||
} while (IndexUtil::BumpIndices(shape(), &indices));
|
||||
} while (IndexUtil::BumpIndices(shape(), absl::MakeSpan(indices)));
|
||||
}
|
||||
|
||||
template <typename NativeT>
|
||||
|
@ -353,11 +353,11 @@ class NearComparator {
|
||||
// bound is exceeded and vice versa.
|
||||
if (is_abs_mismatch) {
|
||||
num_abs_mismatches_++;
|
||||
UpdateErrorBucket(rel_error, &rel_error_buckets_);
|
||||
UpdateErrorBucket(rel_error, absl::MakeSpan(rel_error_buckets_));
|
||||
}
|
||||
if (is_rel_mismatch) {
|
||||
num_rel_mismatches_++;
|
||||
UpdateErrorBucket(abs_error, &abs_error_buckets_);
|
||||
UpdateErrorBucket(abs_error, absl::MakeSpan(abs_error_buckets_));
|
||||
}
|
||||
|
||||
UpdateAbsValueBucket(actual, is_mismatch);
|
||||
@ -579,40 +579,41 @@ constexpr std::array<float, 5> NearComparator<NativeT>::kErrorBucketBounds;
|
||||
Status EqualHelper(const LiteralSlice& expected, const LiteralSlice& actual) {
|
||||
TF_RETURN_IF_ERROR(EqualShapes(expected.shape(), actual.shape()));
|
||||
std::vector<int64> multi_index(expected.shape().dimensions_size(), 0);
|
||||
auto index = absl::MakeSpan(multi_index);
|
||||
Status result;
|
||||
switch (expected.shape().element_type()) {
|
||||
case PRED:
|
||||
result = Equal<bool>(expected, actual, &multi_index, 0);
|
||||
result = Equal<bool>(expected, actual, index, 0);
|
||||
break;
|
||||
case U8:
|
||||
result = Equal<uint8>(expected, actual, &multi_index, 0);
|
||||
result = Equal<uint8>(expected, actual, index, 0);
|
||||
break;
|
||||
case S32:
|
||||
result = Equal<int32>(expected, actual, &multi_index, 0);
|
||||
result = Equal<int32>(expected, actual, index, 0);
|
||||
break;
|
||||
case S64:
|
||||
result = Equal<int64>(expected, actual, &multi_index, 0);
|
||||
result = Equal<int64>(expected, actual, index, 0);
|
||||
break;
|
||||
case U32:
|
||||
result = Equal<uint32>(expected, actual, &multi_index, 0);
|
||||
result = Equal<uint32>(expected, actual, index, 0);
|
||||
break;
|
||||
case U64:
|
||||
result = Equal<uint64>(expected, actual, &multi_index, 0);
|
||||
result = Equal<uint64>(expected, actual, index, 0);
|
||||
break;
|
||||
case BF16:
|
||||
result = Equal<bfloat16>(expected, actual, &multi_index, 0);
|
||||
result = Equal<bfloat16>(expected, actual, index, 0);
|
||||
break;
|
||||
case F16:
|
||||
result = Equal<half>(expected, actual, &multi_index, 0);
|
||||
result = Equal<half>(expected, actual, index, 0);
|
||||
break;
|
||||
case F32:
|
||||
result = Equal<float>(expected, actual, &multi_index, 0);
|
||||
result = Equal<float>(expected, actual, index, 0);
|
||||
break;
|
||||
case F64:
|
||||
result = Equal<double>(expected, actual, &multi_index, 0);
|
||||
result = Equal<double>(expected, actual, index, 0);
|
||||
break;
|
||||
case C64:
|
||||
result = Equal<complex64>(expected, actual, &multi_index, 0);
|
||||
result = Equal<complex64>(expected, actual, index, 0);
|
||||
break;
|
||||
case TUPLE: {
|
||||
for (int i = 0; i < ShapeUtil::TupleElementCount(expected.shape()); ++i) {
|
||||
|
@ -1561,7 +1561,7 @@ TEST_F(LiteralUtilTest, MoveIntoTuple) {
|
||||
|
||||
));
|
||||
|
||||
Literal literal = Literal::MoveIntoTuple(&elements);
|
||||
Literal literal = Literal::MoveIntoTuple(absl::MakeSpan(elements));
|
||||
ASSERT_TRUE(ShapeUtil::IsTuple(literal.shape()));
|
||||
ASSERT_EQ(ShapeUtil::TupleElementCount(literal.shape()), 3);
|
||||
|
||||
|
@ -284,8 +284,9 @@ StatusOr<ScopedShapedBuffer> CpuExecutable::ExecuteAsyncOnStreamImpl(
|
||||
CreateTempArray(memory_allocator, stream->parent()->device_ordinal(),
|
||||
arguments));
|
||||
|
||||
TF_ASSIGN_OR_RETURN(ScopedShapedBuffer result,
|
||||
CreateResultShapedBuffer(run_options, &owning_buffers));
|
||||
TF_ASSIGN_OR_RETURN(
|
||||
ScopedShapedBuffer result,
|
||||
CreateResultShapedBuffer(run_options, absl::MakeSpan(owning_buffers)));
|
||||
|
||||
// At this point, `unowning_buffers` contains unowning pointers to all of our
|
||||
// buffers, and `buffers` contains owning pointers to the non-live-out
|
||||
|
@ -1130,7 +1130,8 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault {
|
||||
static_cast<ElementwiseT>(rhs_literal_data[rhs_linear_index]);
|
||||
}
|
||||
cnt : {}
|
||||
} while (IndexUtil::BumpIndices(window_shape, &rhs_spatial_index));
|
||||
} while (IndexUtil::BumpIndices(window_shape,
|
||||
absl::MakeSpan(rhs_spatial_index)));
|
||||
|
||||
return static_cast<ReturnT>(result_val);
|
||||
};
|
||||
@ -1854,7 +1855,8 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault {
|
||||
embedded_evaluator.ResetVisitStates();
|
||||
}
|
||||
});
|
||||
} while (IndexUtil::BumpIndices(source->shape(), &source_index));
|
||||
} while (
|
||||
IndexUtil::BumpIndices(source->shape(), absl::MakeSpan(source_index)));
|
||||
|
||||
parent_->evaluated_[select_and_scatter] = std::move(result);
|
||||
return Status::OK();
|
||||
@ -2624,7 +2626,8 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault {
|
||||
if (!out_of_bound) {
|
||||
f(base_index);
|
||||
}
|
||||
} while (IndexUtil::BumpIndices(window_shape, &window_index));
|
||||
} while (
|
||||
IndexUtil::BumpIndices(window_shape, absl::MakeSpan(window_index)));
|
||||
}
|
||||
|
||||
template <typename IndexT>
|
||||
|
@ -167,11 +167,11 @@ StatusOr<std::unique_ptr<HloInstruction>> HloInstruction::CreateFromProto(
|
||||
<< proto.called_computation_ids_size();
|
||||
{
|
||||
const auto reduce_operands = all_operands();
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*> inputs(
|
||||
reduce_operands, 0, reduce_operands.size() / 2);
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*> init_values(
|
||||
reduce_operands, reduce_operands.size() / 2,
|
||||
reduce_operands.size());
|
||||
auto inputs = absl::MakeSpan(reduce_operands)
|
||||
.subspan(0, reduce_operands.size() / 2);
|
||||
auto init_values =
|
||||
absl::MakeSpan(reduce_operands)
|
||||
.subspan(reduce_operands.size() / 2, reduce_operands.size());
|
||||
instruction =
|
||||
CreateReduce(proto.shape(), inputs, init_values,
|
||||
std::vector<int64>(proto.dimensions().begin(),
|
||||
|
@ -404,14 +404,12 @@ class HloReduceInstruction : public HloInstruction {
|
||||
|
||||
// Returns the input tensors to be reduced.
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*> inputs() const {
|
||||
return tensorflow::gtl::ArraySlice<HloInstruction*>(operands(), 0,
|
||||
input_count());
|
||||
return absl::MakeSpan(operands()).subspan(0, input_count());
|
||||
}
|
||||
|
||||
// Returns the init values of the reduction.
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*> init_values() const {
|
||||
return tensorflow::gtl::ArraySlice<HloInstruction*>(
|
||||
operands(), input_count(), operand_count());
|
||||
return absl::MakeSpan(operands()).subspan(input_count(), operand_count());
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -997,11 +997,11 @@ bool HloParser::ParseInstruction(HloComputation::Builder* builder,
|
||||
}
|
||||
instruction = builder->AddInstruction(HloInstruction::CreateReduce(
|
||||
shape, /*operands=*/
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*>(operands, 0,
|
||||
operands.size() / 2),
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*>(operands).subspan(
|
||||
0, operands.size() / 2),
|
||||
/*init_values=*/
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*>(
|
||||
operands, operands.size() / 2, operands.size()),
|
||||
tensorflow::gtl::ArraySlice<HloInstruction*>(operands).subspan(
|
||||
operands.size() / 2, operands.size()),
|
||||
*dimensions_to_reduce, *reduce_computation));
|
||||
break;
|
||||
}
|
||||
|
@ -147,16 +147,15 @@ IrArray::Index IrArray::Index::SourceIndexOfReshape(
|
||||
// indices in the same common factor.
|
||||
for (ssize_t k = common_factors.size() - 2; k >= 0; --k) {
|
||||
llvm::Value* logical_linear_index =
|
||||
Index(tensorflow::gtl::ArraySlice<llvm::Value*>(
|
||||
multidim_, common_factors[k].second,
|
||||
Index(tensorflow::gtl::ArraySlice<llvm::Value*>(multidim_).subspan(
|
||||
common_factors[k].second,
|
||||
common_factors[k + 1].second - common_factors[k].second),
|
||||
index_type_)
|
||||
.Linearize(
|
||||
tensorflow::gtl::ArraySlice<int64>(
|
||||
AsInt64Slice(output_shape.dimensions()),
|
||||
common_factors[k].second,
|
||||
common_factors[k + 1].second - common_factors[k].second),
|
||||
builder);
|
||||
.Linearize(AsInt64Slice(output_shape.dimensions())
|
||||
.subspan(common_factors[k].second,
|
||||
common_factors[k + 1].second -
|
||||
common_factors[k].second),
|
||||
builder);
|
||||
// Delinearizes logical_linear_index for the source array in row-major
|
||||
// collapsed order. The first rank-1 indices are the remainder of the
|
||||
// linear index by each dimension size.
|
||||
|
@ -1872,8 +1872,7 @@ ShapeInference::InferDegenerateDimensionBroadcastShape(HloOpcode operation,
|
||||
}
|
||||
int64 num_reduced_args = arg_shapes.size() / 2;
|
||||
|
||||
tensorflow::gtl::ArraySlice<const Shape*> reduced_args(arg_shapes, 0,
|
||||
num_reduced_args);
|
||||
auto reduced_args = arg_shapes.subspan(0, num_reduced_args);
|
||||
// Check that all of the reduced tensors have the same dimensions. The element
|
||||
// types may be different.
|
||||
for (int64 i = 1; i < num_reduced_args; ++i) {
|
||||
@ -1897,8 +1896,7 @@ ShapeInference::InferDegenerateDimensionBroadcastShape(HloOpcode operation,
|
||||
}
|
||||
}
|
||||
|
||||
tensorflow::gtl::ArraySlice<const Shape*> init_values(
|
||||
arg_shapes, num_reduced_args, arg_shapes.size());
|
||||
auto init_values = arg_shapes.subspan(num_reduced_args, arg_shapes.size());
|
||||
std::vector<PrimitiveType> element_types;
|
||||
for (const Shape* arg : reduced_args) {
|
||||
element_types.push_back(arg->element_type());
|
||||
|
@ -96,7 +96,9 @@ class SparseIndexArray {
|
||||
int64 max_indices() const { return max_indices_; }
|
||||
|
||||
// Returns a pointer to the int64 array that holds the sparse indices.
|
||||
tensorflow::gtl::MutableArraySlice<int64> mutable_data() { return &indices_; }
|
||||
tensorflow::gtl::MutableArraySlice<int64> mutable_data() {
|
||||
return absl::MakeSpan(indices_);
|
||||
}
|
||||
tensorflow::gtl::ArraySlice<int64> data() const { return indices_; }
|
||||
|
||||
// Sorts this sparse index array along with the set of corresponding values.
|
||||
|
@ -33,7 +33,7 @@ TEST(SparseIndexArrayTest, Sort) {
|
||||
std::vector<double> values = {
|
||||
12.0, 13.0, 11.0, 15.0, 14.0, 16.0,
|
||||
};
|
||||
a.SortWithValues<double>(&values);
|
||||
a.SortWithValues<double>(absl::MakeSpan(values));
|
||||
ASSERT_EQ(a.data(), std::vector<int64>({1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5,
|
||||
6, 7, 6, 7, 8}));
|
||||
ASSERT_EQ(values, std::vector<double>({11.0, 12.0, 13.0, 14.0, 15.0, 16.0}));
|
||||
|
@ -113,7 +113,7 @@ class FusionTest : public HloTestBase {
|
||||
hlos[0] = builder.AddInstruction(std::move(root_hlo));
|
||||
hlo_module->AddEntryComputation(builder.Build())
|
||||
->CreateFusionInstruction(
|
||||
ArraySlice<HloInstruction*>(hlos, 0, Arity + 1),
|
||||
ArraySlice<HloInstruction*>(hlos).subspan(0, Arity + 1),
|
||||
HloInstruction::FusionKind::kLoop);
|
||||
|
||||
auto expected = LiteralUtil::CreateR2FromArray2D(answer_data);
|
||||
|
@ -96,8 +96,8 @@ class MultiOutputFusionTest : public HloTestBase {
|
||||
auto computation = hlo_module->AddEntryComputation(builder.Build(dot));
|
||||
|
||||
if (manual_fusion) {
|
||||
auto tuple = computation->AddInstruction(HloInstruction::CreateTuple(
|
||||
ArraySlice<HloInstruction*>({sub, add2}, 0, 2)));
|
||||
auto tuple =
|
||||
computation->AddInstruction(HloInstruction::CreateTuple({sub, add2}));
|
||||
auto gte0 = computation->AddInstruction(
|
||||
HloInstruction::CreateGetTupleElement(elem_shape2, tuple, 0));
|
||||
auto gte1 = computation->AddInstruction(
|
||||
@ -159,8 +159,8 @@ class MultiOutputFusionTest : public HloTestBase {
|
||||
auto computation = hlo_module->AddEntryComputation(builder.Build(dot));
|
||||
|
||||
if (manual_fusion) {
|
||||
auto tuple = computation->AddInstruction(HloInstruction::CreateTuple(
|
||||
ArraySlice<HloInstruction*>({sub_U8, add}, 0, 2)));
|
||||
auto tuple = computation->AddInstruction(
|
||||
HloInstruction::CreateTuple({sub_U8, add}));
|
||||
|
||||
auto gte0 = computation->AddInstruction(
|
||||
HloInstruction::CreateGetTupleElement(elem_shape_U8, tuple, 0));
|
||||
|
@ -293,9 +293,10 @@ bool IsPermutation(tensorflow::gtl::ArraySlice<int64> permutation, int64 rank);
|
||||
// Precondition:
|
||||
// 1. `permutation` is a permutation of 0..permutation.size()-1.
|
||||
// 2. permutation.size() == input.size().
|
||||
template <template <typename...> class C, typename T>
|
||||
std::vector<T> Permute(tensorflow::gtl::ArraySlice<int64> permutation,
|
||||
C<T> input) {
|
||||
template <typename Container>
|
||||
std::vector<typename Container::value_type> Permute(
|
||||
tensorflow::gtl::ArraySlice<int64> permutation, const Container& input) {
|
||||
using T = typename Container::value_type;
|
||||
tensorflow::gtl::ArraySlice<T> data(input);
|
||||
CHECK(IsPermutation(permutation, data.size()));
|
||||
std::vector<T> output(data.size());
|
||||
@ -305,17 +306,6 @@ std::vector<T> Permute(tensorflow::gtl::ArraySlice<int64> permutation,
|
||||
return output;
|
||||
}
|
||||
|
||||
// Override of the above that works around compile failures with gcc 7.1.1.
|
||||
// For details see https://github.com/tensorflow/tensorflow/issues/10843
|
||||
// Hide this workaround from MSVC as it causes ambiguous error.
|
||||
#ifndef _MSC_VER
|
||||
template <typename T>
|
||||
std::vector<T> Permute(tensorflow::gtl::ArraySlice<int64> permutation,
|
||||
const std::vector<T>& input) {
|
||||
return Permute<std::vector, T>(permutation, input);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Inverts a permutation, i.e., output_permutation[input_permutation[i]] = i.
|
||||
std::vector<int64> InversePermutation(
|
||||
tensorflow::gtl::ArraySlice<int64> input_permutation);
|
||||
|
@ -2471,6 +2471,7 @@ tf_cuda_library(
|
||||
|
||||
cc_header_only_library(
|
||||
name = "framework_internal_headers_lib",
|
||||
includes = ["../../external/com_google_absl"],
|
||||
deps = [
|
||||
":lib",
|
||||
":lib_internal",
|
||||
@ -2559,6 +2560,7 @@ cc_header_only_library(
|
||||
# ABSL headers get dropped, so we add them back here.
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
includes = ["../../external/com_google_absl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":framework",
|
||||
@ -2568,6 +2570,7 @@ cc_header_only_library(
|
||||
|
||||
cc_header_only_library(
|
||||
name = "stream_executor_headers_lib",
|
||||
includes = ["../../external/com_google_absl"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":stream_executor",
|
||||
@ -3219,7 +3222,6 @@ tf_cc_tests(
|
||||
"lib/core/status_test.cc",
|
||||
"lib/core/stringpiece_test.cc",
|
||||
"lib/core/threadpool_test.cc",
|
||||
"lib/gtl/array_slice_test.cc",
|
||||
"lib/gtl/cleanup_test.cc",
|
||||
"lib/gtl/compactptrset_test.cc",
|
||||
"lib/gtl/edit_distance_test.cc",
|
||||
|
@ -432,9 +432,9 @@ Status Conv2DShape(shape_inference::InferenceContext* c) {
|
||||
DimensionHandle batch_size_dim;
|
||||
DimensionHandle input_depth_dim;
|
||||
gtl::InlinedVector<DimensionHandle, 2> input_spatial_dims(2);
|
||||
TF_RETURN_IF_ERROR(DimensionsFromShape(conv_input_shape, data_format,
|
||||
&batch_size_dim, &input_spatial_dims,
|
||||
&input_depth_dim, c));
|
||||
TF_RETURN_IF_ERROR(DimensionsFromShape(
|
||||
conv_input_shape, data_format, &batch_size_dim,
|
||||
absl::MakeSpan(input_spatial_dims), &input_depth_dim, c));
|
||||
|
||||
DimensionHandle output_depth_dim = c->Dim(
|
||||
filter_shape, GetFilterDimIndex<num_spatial_dims>(filter_format, 'O'));
|
||||
|
@ -89,9 +89,9 @@ class BaseCandidateSamplerOp : public OpKernel {
|
||||
// Pick sampled candidates.
|
||||
auto local_gen = generator_.ReserveSamples32(samples32);
|
||||
random::SimplePhilox random(&local_gen);
|
||||
sampler_->SampleBatchGetExpectedCount(&random, unique_, &sampled_candidate,
|
||||
&sampled_expected_count,
|
||||
true_candidate, &true_expected_count);
|
||||
sampler_->SampleBatchGetExpectedCount(&random, unique_, sampled_candidate,
|
||||
sampled_expected_count,
|
||||
true_candidate, true_expected_count);
|
||||
|
||||
if (sampler_->NeedsUpdates()) {
|
||||
sampler_->Update(true_candidate);
|
||||
|
@ -45,7 +45,7 @@ class RangeSamplerTest : public ::testing::Test {
|
||||
// Using a fixed random seed to make the test deterministic.
|
||||
random::PhiloxRandom philox(123, 17);
|
||||
random::SimplePhilox rnd(&philox);
|
||||
sampler_->SampleBatch(&rnd, false, &a);
|
||||
sampler_->SampleBatch(&rnd, false, absl::MakeSpan(a));
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
int64 val = a[i];
|
||||
ASSERT_GE(val, 0);
|
||||
@ -251,8 +251,9 @@ TEST_F(RangeSamplerTest, All) {
|
||||
extras[0] = 0;
|
||||
extras[1] = batch_size - 1;
|
||||
sampler_->SampleBatchGetExpectedCount(nullptr, // no random numbers needed
|
||||
false, &batch, &batch_expected, extras,
|
||||
&extras_expected);
|
||||
false, absl::MakeSpan(batch),
|
||||
absl::MakeSpan(batch_expected), extras,
|
||||
absl::MakeSpan(extras_expected));
|
||||
for (int i = 0; i < batch_size; i++) {
|
||||
EXPECT_EQ(i, batch[i]);
|
||||
EXPECT_EQ(1, batch_expected[i]);
|
||||
@ -281,17 +282,18 @@ TEST_F(RangeSamplerTest, Unique) {
|
||||
std::vector<float> expected(range);
|
||||
|
||||
// Sample one batch and get the expected counts of all values
|
||||
sampler_->SampleBatchGetExpectedCount(
|
||||
&rnd, true, &batch, MutableArraySlice<float>(), all_values, &expected);
|
||||
sampler_->SampleBatchGetExpectedCount(&rnd, true, absl::MakeSpan(batch),
|
||||
MutableArraySlice<float>(), all_values,
|
||||
absl::MakeSpan(expected));
|
||||
// Check that all elements are unique
|
||||
std::set<int64> s(batch.begin(), batch.end());
|
||||
CHECK_EQ(batch_size, s.size());
|
||||
|
||||
for (int trial = 0; trial < num_batches; trial++) {
|
||||
std::vector<float> trial_expected(range);
|
||||
sampler_->SampleBatchGetExpectedCount(&rnd, true, &batch,
|
||||
MutableArraySlice<float>(),
|
||||
all_values, &trial_expected);
|
||||
sampler_->SampleBatchGetExpectedCount(
|
||||
&rnd, true, absl::MakeSpan(batch), MutableArraySlice<float>(),
|
||||
all_values, absl::MakeSpan(trial_expected));
|
||||
for (int i = 0; i < range; i++) {
|
||||
EXPECT_NEAR(expected[i], trial_expected[i], expected[i] * 0.5);
|
||||
}
|
||||
@ -318,8 +320,8 @@ TEST_F(RangeSamplerTest, Avoid) {
|
||||
|
||||
// We expect to pick all elements of [0, 100) except the avoided two.
|
||||
sampler_->SampleBatchGetExpectedCountAvoid(
|
||||
&rnd, true, &batch, MutableArraySlice<float>(), ArraySlice<int64>(),
|
||||
MutableArraySlice<float>(), avoided);
|
||||
&rnd, true, absl::MakeSpan(batch), MutableArraySlice<float>(),
|
||||
ArraySlice<int64>(), MutableArraySlice<float>(), avoided);
|
||||
|
||||
int sum = 0;
|
||||
for (auto val : batch) {
|
||||
|
@ -269,7 +269,7 @@ void SetSizeOp<T>::Compute(OpKernelContext* ctx) {
|
||||
|
||||
// Group by all but last dimension, create a set of group values, and add set
|
||||
// size to output.
|
||||
VarDimArray group_ix(set_st.order(), 0, set_st.order().size() - 1);
|
||||
VarDimArray group_ix = set_st.order().subspan(0, set_st.order().size() - 1);
|
||||
std::set<T> group_set;
|
||||
for (const auto& group : set_st.group(group_ix)) {
|
||||
PopulateFromSparseGroup<T>(ctx, group, set_st.shape(), &group_set);
|
||||
@ -500,8 +500,8 @@ void SetOperationOp<T>::ComputeDenseToSparse(OpKernelContext* ctx) const {
|
||||
|
||||
std::set<T> set1_group_set;
|
||||
std::set<T> set2_group_set;
|
||||
auto set2_grouper = set2_st.group(
|
||||
VarDimArray(set2_st.order(), 0, set2_st.order().size() - 1));
|
||||
auto set2_grouper =
|
||||
set2_st.group(set2_st.order().subspan(0, set2_st.order().size() - 1));
|
||||
auto set2_group_it = set2_grouper.begin();
|
||||
std::vector<int64> group_indices;
|
||||
int64 num_elements;
|
||||
@ -621,11 +621,11 @@ void SetOperationOp<T>::ComputeSparseToSparse(OpKernelContext* ctx) const {
|
||||
|
||||
std::set<T> set1_group_set;
|
||||
std::set<T> set2_group_set;
|
||||
auto set1_grouper = set1_st.group(
|
||||
VarDimArray(set1_st.order(), 0, set1_st.order().size() - 1));
|
||||
auto set1_grouper =
|
||||
set1_st.group(set1_st.order().subspan(0, set1_st.order().size() - 1));
|
||||
auto set1_group_it = set1_grouper.begin();
|
||||
auto set2_grouper = set2_st.group(
|
||||
VarDimArray(set2_st.order(), 0, set2_st.order().size() - 1));
|
||||
auto set2_grouper =
|
||||
set2_st.group(set2_st.order().subspan(0, set2_st.order().size() - 1));
|
||||
auto set2_group_it = set2_grouper.begin();
|
||||
|
||||
// Group by rows, and iterate over rows of both sets in parallel, creating a
|
||||
|
@ -90,7 +90,7 @@ class SparseSoftmaxOp : public OpKernel {
|
||||
// { 0, ..., rank-1 }.
|
||||
const ArraySlice<int64> kReorderDims(dims);
|
||||
// All but the last dim -- the class dimension to be max-reduced along.
|
||||
const ArraySlice<int64> kGroupByDims(kReorderDims, 0, rank - 1);
|
||||
const ArraySlice<int64> kGroupByDims = kReorderDims.subspan(0, rank - 1);
|
||||
st.Reorder<T>(kReorderDims);
|
||||
int count = 0;
|
||||
|
||||
|
@ -13,293 +13,22 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
// An ArraySlice<T> represents an immutable array of elements of type
|
||||
// T. It has a length "length", and a base pointer "ptr", and the
|
||||
// array it represents contains the elements "ptr[0] .. ptr[len-1]".
|
||||
// The backing store for the array is *not* owned by the ArraySlice
|
||||
// object, and clients must arrange for the backing store to remain
|
||||
// live while the ArraySlice object is in use.
|
||||
//
|
||||
// An ArraySlice<T> is somewhat analogous to a StringPiece, but for
|
||||
// array elements of type T.
|
||||
//
|
||||
// Implicit conversion operations are provided from types such as
|
||||
// std::vector<T> and util::gtl::InlinedVector<T, N>. Note that ArraySlice
|
||||
// objects constructed from types in this way may be invalidated by
|
||||
// any operations that mutate the underlying vector.
|
||||
//
|
||||
// One common use for ArraySlice is when passing arguments to a
|
||||
// routine where you want to be able to accept a variety of array
|
||||
// types (e.g. a vector, a util::gtl::InlinedVector, a C-style array,
|
||||
// etc.). The usual approach here is to have the client explicitly
|
||||
// pass in a pointer and a length, as in:
|
||||
//
|
||||
// void MyRoutine(const int* elems, int N) {
|
||||
// for (int i = 0; i < N; i++) { .. do something with elems[i] .. }
|
||||
// }
|
||||
//
|
||||
// Unfortunately, this leads to ugly and error-prone code at the call site:
|
||||
//
|
||||
// std::vector<int> my_vector;
|
||||
// MyRoutine(vector_as_array(&my_vector), my_vector.size());
|
||||
//
|
||||
// util::gtl::InlinedVector<int, 4> my_inline_vector;
|
||||
// MyRoutine(my_inline_vector.array(), my_inline_vector.size());
|
||||
//
|
||||
// int my_array[10];
|
||||
// MyRoutine(my_array, 10);
|
||||
//
|
||||
// Instead, you can use an ArraySlice as the argument to the routine:
|
||||
//
|
||||
// void MyRoutine(ArraySlice<int> a) {
|
||||
// for (int i = 0; i < a.size(); i++) { .. do something with a[i] .. }
|
||||
// }
|
||||
//
|
||||
// This makes the call sites cleaner, for the most part:
|
||||
//
|
||||
// std::vector<int> my_vector;
|
||||
// MyRoutine(my_vector);
|
||||
//
|
||||
// util::gtl::InlinedVector<int, 4> my_inline_vector;
|
||||
// MyRoutine(my_inline_vector);
|
||||
//
|
||||
// int my_array[10];
|
||||
// MyRoutine(my_array);
|
||||
//
|
||||
// int* my_array = new int[10];
|
||||
// MyRoutine(gtl::ArraySlice<int>(my_array, 10));
|
||||
//
|
||||
// MutableArraySlice<T> represents a mutable array of elements, and, like
|
||||
// ArraySlice, does not own the backing store. The implicit constructors it
|
||||
// provides allow functions not to worry about whether their mutable arguments
|
||||
// refer to vectors, arrays, proto2::RepeatedFields, etc.:
|
||||
//
|
||||
// void MyMutatingRoutine(MutableArraySlice<int> a) {
|
||||
// for (int i = 0; i < a.size(); i++) { .. mutate a[i] .. }
|
||||
// }
|
||||
//
|
||||
// std::vector<int> my_vector;
|
||||
// MyMutatingRoutine(&my_vector);
|
||||
//
|
||||
// int my_array[10];
|
||||
// MyMutatingRoutine(my_array);
|
||||
//
|
||||
// int* my_array = new int[10];
|
||||
// MyMutatingRoutine(gtl::MutableArraySlice<int>(my_array, 10));
|
||||
//
|
||||
// MyProto my_proto;
|
||||
// for (int i = 0; i < 10; ++i) { my_proto.add_value(i); }
|
||||
// MyMutatingRoutine(my_proto.mutable_value());
|
||||
|
||||
#ifndef TENSORFLOW_CORE_LIB_GTL_ARRAY_SLICE_H_
|
||||
#define TENSORFLOW_CORE_LIB_GTL_ARRAY_SLICE_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "tensorflow/core/lib/gtl/array_slice_internal.h"
|
||||
#include "absl/types/span.h"
|
||||
// TODO(timshen): This is kept only because lots of targets transitively depend
|
||||
// on it. Remove all targets' dependencies.
|
||||
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace gtl {
|
||||
|
||||
template <typename T>
|
||||
class ArraySlice {
|
||||
private:
|
||||
typedef array_slice_internal::ArraySliceImpl<T> Impl;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename Impl::pointer pointer;
|
||||
typedef typename Impl::const_pointer const_pointer;
|
||||
typedef typename Impl::reference reference;
|
||||
typedef typename Impl::const_reference const_reference;
|
||||
typedef typename Impl::iterator iterator;
|
||||
typedef typename Impl::const_iterator const_iterator;
|
||||
typedef typename Impl::reverse_iterator reverse_iterator;
|
||||
typedef typename Impl::const_reverse_iterator const_reverse_iterator;
|
||||
typedef typename Impl::size_type size_type;
|
||||
typedef typename Impl::difference_type difference_type;
|
||||
|
||||
static const size_type npos = Impl::npos;
|
||||
|
||||
ArraySlice() : impl_(nullptr, 0) {}
|
||||
ArraySlice(const_pointer array, size_type length) : impl_(array, length) {}
|
||||
|
||||
// Implicit conversion constructors
|
||||
ArraySlice(const std::vector<value_type>& v) // NOLINT(runtime/explicit)
|
||||
: impl_(v.data(), v.size()) {}
|
||||
|
||||
template <size_t N>
|
||||
ArraySlice(const value_type (&a)[N]) // NOLINT(runtime/explicit)
|
||||
: impl_(a, N) {}
|
||||
|
||||
template <int N>
|
||||
ArraySlice(const InlinedVector<value_type, N>& v) // NOLINT(runtime/explicit)
|
||||
: impl_(v.data(), v.size()) {}
|
||||
|
||||
// The constructor for any class supplying 'data() const' that returns either
|
||||
// const T* or a less const-qualified version of it, and 'some_integral_type
|
||||
// size() const'. proto2::RepeatedField<T>, string and (since C++11)
|
||||
// std::vector<T,A> and std::array<T, N> are examples of this. See
|
||||
// array_slice_internal.h for details.
|
||||
template <typename V,
|
||||
typename = typename Impl::template EnableIfConvertibleFrom<V>>
|
||||
ArraySlice(const V& v) // NOLINT(runtime/explicit)
|
||||
: impl_(v) {}
|
||||
|
||||
// Implicitly constructs an ArraySlice from an initializer list. This makes it
|
||||
// possible to pass a brace-enclosed initializer list to a function expecting
|
||||
// an ArraySlice:
|
||||
// void Process(ArraySlice<int> x);
|
||||
// Process({1, 2, 3});
|
||||
// The data referenced by the initializer_list must outlive this
|
||||
// ArraySlice. For example, "ArraySlice<int> s={1,2};" and "return
|
||||
// ArraySlice<int>({3,4});" are errors, as the resulting ArraySlice may
|
||||
// reference data that is no longer valid.
|
||||
ArraySlice(std::initializer_list<value_type> v) // NOLINT(runtime/explicit)
|
||||
: impl_(v.begin(), v.size()) {}
|
||||
|
||||
// Substring of another ArraySlice.
|
||||
// pos must be non-negative and <= x.length().
|
||||
// len must be non-negative and will be pinned to at most x.length() - pos.
|
||||
// If len==npos, the substring continues till the end of x.
|
||||
ArraySlice(const ArraySlice& x, size_type pos, size_type len)
|
||||
: impl_(x.impl_, pos, len) {}
|
||||
|
||||
const_pointer data() const { return impl_.data(); }
|
||||
size_type size() const { return impl_.size(); }
|
||||
size_type length() const { return size(); }
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void clear() { impl_.clear(); }
|
||||
|
||||
const_reference operator[](size_type i) const { return impl_[i]; }
|
||||
const_reference at(size_type i) const { return impl_.at(i); }
|
||||
const_reference front() const { return impl_.front(); }
|
||||
const_reference back() const { return impl_.back(); }
|
||||
|
||||
const_iterator begin() const { return impl_.begin(); }
|
||||
const_iterator end() const { return impl_.end(); }
|
||||
const_reverse_iterator rbegin() const { return impl_.rbegin(); }
|
||||
const_reverse_iterator rend() const { return impl_.rend(); }
|
||||
|
||||
void remove_prefix(size_type n) { impl_.remove_prefix(n); }
|
||||
void remove_suffix(size_type n) { impl_.remove_suffix(n); }
|
||||
|
||||
// These relational operators have the same semantics as the
|
||||
// std::vector<T> relational operators: they do deep (element-wise)
|
||||
// comparisons. Array slices are equal iff their size is the same
|
||||
// and all their elements are equal.
|
||||
bool operator==(ArraySlice<T> other) const { return impl_ == other.impl_; }
|
||||
bool operator!=(ArraySlice<T> other) const { return impl_ != other.impl_; }
|
||||
|
||||
private:
|
||||
Impl impl_;
|
||||
};
|
||||
|
||||
// Mutable version of ArraySlice, which allows the clients to mutate the
|
||||
// underlying data. It is implicitly convertible to ArraySlice since it provides
|
||||
// the data() and size() methods with correct signatures. When a
|
||||
// MutableArraySlice is created from a pointer to a container (as opposed to raw
|
||||
// memory pointer), the pointer must not be null.
|
||||
//
|
||||
// A note on const-ness: "mutable" here refers to the mutability of the
|
||||
// underlying data, not of the slice itself. It is perfectly reasonable to have
|
||||
// a variable of type "const MutableArraySlice<T>"; this means that the bounds
|
||||
// of the view on the array cannot be changed, but the underlying data in the
|
||||
// array still may be modified. This is akin to a "T* const" pointer, as opposed
|
||||
// to a "const T*" pointer (corresponding to a non-const ArraySlice<T>).
|
||||
template <typename T>
|
||||
class MutableArraySlice {
|
||||
private:
|
||||
typedef array_slice_internal::MutableArraySliceImpl<T> Impl;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename Impl::pointer pointer;
|
||||
typedef typename Impl::const_pointer const_pointer;
|
||||
typedef typename Impl::reference reference;
|
||||
typedef typename Impl::const_reference const_reference;
|
||||
typedef typename Impl::iterator iterator;
|
||||
typedef typename Impl::const_iterator const_iterator;
|
||||
typedef typename Impl::reverse_iterator reverse_iterator;
|
||||
typedef typename Impl::const_reverse_iterator const_reverse_iterator;
|
||||
typedef typename Impl::size_type size_type;
|
||||
typedef typename Impl::difference_type difference_type;
|
||||
|
||||
static const size_type npos = Impl::npos;
|
||||
|
||||
MutableArraySlice() : impl_(nullptr, 0) {}
|
||||
MutableArraySlice(pointer array, size_type length) : impl_(array, length) {}
|
||||
|
||||
// Implicit conversion constructors
|
||||
MutableArraySlice(std::vector<value_type>* v) // NOLINT(runtime/explicit)
|
||||
: impl_(v->data(), v->size()) {}
|
||||
|
||||
template <size_t N>
|
||||
MutableArraySlice(value_type (&a)[N]) // NOLINT(runtime/explicit)
|
||||
: impl_(a, N) {}
|
||||
|
||||
template <int N>
|
||||
MutableArraySlice(
|
||||
InlinedVector<value_type, N>* v) // NOLINT(runtime/explicit)
|
||||
: impl_(v->data(), v->size()) {}
|
||||
|
||||
// The constructor for any class supplying 'T* data()' or 'T* mutable_data()'
|
||||
// (the former is called if both exist), and 'some_integral_type size()
|
||||
// const'. proto2::RepeatedField is an example of this. Also supports string
|
||||
// arguments, when T==char. The appropriate ctor is selected using SFINAE. See
|
||||
// array_slice_internal.h for details.
|
||||
template <typename V,
|
||||
typename = typename Impl::template EnableIfConvertibleFrom<V>>
|
||||
MutableArraySlice(V* v) // NOLINT(runtime/explicit)
|
||||
: impl_(v) {}
|
||||
|
||||
// Substring of another MutableArraySlice.
|
||||
// pos must be non-negative and <= x.length().
|
||||
// len must be non-negative and will be pinned to at most x.length() - pos.
|
||||
// If len==npos, the substring continues till the end of x.
|
||||
MutableArraySlice(const MutableArraySlice& x, size_type pos, size_type len)
|
||||
: impl_(x.impl_, pos, len) {}
|
||||
|
||||
// Accessors.
|
||||
pointer data() const { return impl_.data(); }
|
||||
size_type size() const { return impl_.size(); }
|
||||
size_type length() const { return size(); }
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void clear() { impl_.clear(); }
|
||||
|
||||
reference operator[](size_type i) const { return impl_[i]; }
|
||||
reference at(size_type i) const { return impl_.at(i); }
|
||||
reference front() const { return impl_.front(); }
|
||||
reference back() const { return impl_.back(); }
|
||||
|
||||
iterator begin() const { return impl_.begin(); }
|
||||
iterator end() const { return impl_.end(); }
|
||||
reverse_iterator rbegin() const { return impl_.rbegin(); }
|
||||
reverse_iterator rend() const { return impl_.rend(); }
|
||||
|
||||
void remove_prefix(size_type n) { impl_.remove_prefix(n); }
|
||||
void remove_suffix(size_type n) { impl_.remove_suffix(n); }
|
||||
|
||||
bool operator==(ArraySlice<T> other) const {
|
||||
return ArraySlice<T>(*this) == other;
|
||||
}
|
||||
bool operator!=(ArraySlice<T> other) const {
|
||||
return ArraySlice<T>(*this) != other;
|
||||
}
|
||||
|
||||
private:
|
||||
Impl impl_;
|
||||
};
|
||||
using ArraySlice = absl::Span<const T>;
|
||||
|
||||
template <typename T>
|
||||
const typename ArraySlice<T>::size_type ArraySlice<T>::npos;
|
||||
template <typename T>
|
||||
const typename MutableArraySlice<T>::size_type MutableArraySlice<T>::npos;
|
||||
using MutableArraySlice = absl::Span<T>;
|
||||
|
||||
} // namespace gtl
|
||||
} // namespace tensorflow
|
||||
|
@ -1,269 +0,0 @@
|
||||
/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
|
||||
// NOT FOR INCLUSION BY CLIENT CODE. This file is only to be included by
|
||||
// array_slice.h.
|
||||
|
||||
// Helper functions and templates for ArraySlice.
|
||||
|
||||
#ifndef TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
|
||||
#define TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace gtl {
|
||||
namespace array_slice_internal {
|
||||
|
||||
// Template logic for generic constructors.
|
||||
|
||||
// Wrappers whose Get() delegates to the appropriate method of a container, and
|
||||
// is defined when this method exists. Delegates to the const method if C is a
|
||||
// const type.
|
||||
struct Data {
|
||||
template <typename C>
|
||||
static decltype(std::declval<C>().data()) Get(C* v) {
|
||||
return v->data();
|
||||
}
|
||||
};
|
||||
|
||||
struct MutableData {
|
||||
template <typename C>
|
||||
static decltype(std::declval<C>().mutable_data()) Get(C* v) {
|
||||
return v->mutable_data();
|
||||
}
|
||||
};
|
||||
|
||||
struct Size {
|
||||
template <typename C>
|
||||
static decltype(std::declval<C>().size()) Get(C* v) {
|
||||
return v->size();
|
||||
}
|
||||
};
|
||||
|
||||
struct MutableStringData {
|
||||
// Defined only for string.
|
||||
static char* Get(string* v) { return v->empty() ? nullptr : &*v->begin(); }
|
||||
};
|
||||
|
||||
// Checks whether M::Get(C*) is defined and has a return type R such that
|
||||
// Checker::valid<R>()==true.
|
||||
template <typename M, typename Checker, typename C>
|
||||
struct HasGetHelper : public M {
|
||||
private:
|
||||
struct None {};
|
||||
// M::Get is selected when it is viable. Get(...) is selected otherwise.
|
||||
using M::Get;
|
||||
static None Get(...);
|
||||
|
||||
public:
|
||||
static constexpr bool HasGet() {
|
||||
using Result = decltype(Get(std::declval<C*>()));
|
||||
return !std::is_same<Result, None>() && Checker::template valid<Result>();
|
||||
}
|
||||
};
|
||||
|
||||
// Defines HasGet() for a particular method, container, and checker. If
|
||||
// HasGet()==true, provides Get() that delegates to the method.
|
||||
template <typename M, typename Checker, typename C,
|
||||
bool /*has_get*/ = HasGetHelper<M, Checker, C>::HasGet()>
|
||||
struct Wrapper {
|
||||
static constexpr bool HasGet() { return false; }
|
||||
};
|
||||
|
||||
template <typename M, typename Checker, typename C>
|
||||
struct Wrapper<M, Checker, C, true> {
|
||||
static constexpr bool HasGet() { return true; }
|
||||
static decltype(M::Get(std::declval<C*>())) Get(C* v) { return M::Get(v); }
|
||||
};
|
||||
|
||||
// Type checker for a method returning an integral value.
|
||||
struct SizeChecker {
|
||||
template <typename R>
|
||||
static constexpr bool valid() {
|
||||
return std::is_integral<R>::value;
|
||||
}
|
||||
};
|
||||
|
||||
// Type checker for a method returning either a pointer to T or a less const
|
||||
// version of that.
|
||||
template <typename T>
|
||||
struct DataChecker {
|
||||
// We want to enable conversion from std::vector<T*> to ArraySlice<const T*>
|
||||
// but
|
||||
// disable conversion from std::vector<Derived> to ArraySlice<Base>. Here we
|
||||
// use
|
||||
// the fact that U** is convertible to Q* const* if and only if Q is the same
|
||||
// type or a more cv-qualified version of U.
|
||||
template <typename R>
|
||||
static constexpr bool valid() {
|
||||
return std::is_convertible<R*, T* const*>::value;
|
||||
}
|
||||
};
|
||||
|
||||
// Aliases to A if A::HasGet()==true, or to B otherwise.
|
||||
template <typename A, typename B>
|
||||
using FirstWithGet = typename std::conditional<A::HasGet(), A, B>::type;
|
||||
|
||||
// Wraps C::data() const, returning a pointer to const data.
|
||||
template <typename T, typename C>
|
||||
using ContainerData = Wrapper<Data, DataChecker<const T>, const C>;
|
||||
|
||||
// Wraps a method returning a pointer to mutable data. Prefers data() over
|
||||
// mutable_data(), and handles strings when T==char. If data() returns a pointer
|
||||
// to mutable data, it is most likely overloaded, but may also be a single
|
||||
// method 'T* C::data() const' in a non-STL-compliant container.
|
||||
template <typename T, typename C>
|
||||
using ContainerMutableData =
|
||||
FirstWithGet<Wrapper<Data, DataChecker<T>, C>,
|
||||
FirstWithGet<Wrapper<MutableData, DataChecker<T>, C>,
|
||||
Wrapper<MutableStringData, DataChecker<T>, C>>>;
|
||||
|
||||
// Wraps C::size() const.
|
||||
template <typename C>
|
||||
using ContainerSize = Wrapper<Size, SizeChecker, const C>;
|
||||
|
||||
// Implementation class for ArraySlice and MutableArraySlice. In the case of
|
||||
// ArraySlice, T will be a const type; for MutableArraySlice, T will be a
|
||||
// mutable type.
|
||||
template <typename T>
|
||||
class ArraySliceImplBase {
|
||||
public:
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef pointer iterator;
|
||||
typedef const_pointer const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
static const size_type npos = static_cast<size_type>(-1);
|
||||
|
||||
ArraySliceImplBase(pointer array, size_type length)
|
||||
: ptr_(array), length_(length) {}
|
||||
|
||||
// Substring of another ArraySlice.
|
||||
// pos must be non-negative and <= x.length().
|
||||
// len must be non-negative and will be pinned to at most x.length() - pos.
|
||||
ArraySliceImplBase(const ArraySliceImplBase& x, size_type pos, size_type len)
|
||||
: ptr_(x.ptr_ + pos), length_(std::min(x.length_ - pos, len)) {}
|
||||
|
||||
// Some of the const methods below return pointers and references to mutable
|
||||
// data. This is only the case in this internal class; ArraySlice and
|
||||
// MutableArraySlice provide deep-constness.
|
||||
|
||||
pointer data() const { return ptr_; }
|
||||
size_type size() const { return length_; }
|
||||
|
||||
void clear() {
|
||||
ptr_ = nullptr;
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
reference operator[](size_type i) const { return ptr_[i]; }
|
||||
reference at(size_type i) const {
|
||||
DCHECK_LT(i, length_);
|
||||
return ptr_[i];
|
||||
}
|
||||
reference front() const {
|
||||
DCHECK_GT(length_, 0);
|
||||
return ptr_[0];
|
||||
}
|
||||
reference back() const {
|
||||
DCHECK_GT(length_, 0);
|
||||
return ptr_[length_ - 1];
|
||||
}
|
||||
|
||||
void remove_prefix(size_type n) {
|
||||
DCHECK_GE(length_, n);
|
||||
ptr_ += n;
|
||||
length_ -= n;
|
||||
}
|
||||
void remove_suffix(size_type n) {
|
||||
DCHECK_GE(length_, n);
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
iterator begin() const { return ptr_; }
|
||||
iterator end() const { return ptr_ + length_; }
|
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); }
|
||||
reverse_iterator rend() const { return reverse_iterator(begin()); }
|
||||
|
||||
bool operator==(const ArraySliceImplBase& other) const {
|
||||
if (size() != other.size()) return false;
|
||||
if (data() == other.data()) return true;
|
||||
return std::equal(data(), data() + size(), other.data());
|
||||
}
|
||||
bool operator!=(const ArraySliceImplBase& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
pointer ptr_;
|
||||
size_type length_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ArraySliceImpl : public ArraySliceImplBase<const T> {
|
||||
public:
|
||||
using ArraySliceImplBase<const T>::ArraySliceImplBase;
|
||||
|
||||
// Defined iff the data and size accessors for the container C have been
|
||||
// defined.
|
||||
template <typename C>
|
||||
using EnableIfConvertibleFrom =
|
||||
typename std::enable_if<ContainerData<T, C>::HasGet() &&
|
||||
ContainerSize<C>::HasGet()>::type;
|
||||
|
||||
// Constructs from a container when EnableIfConvertibleFrom is
|
||||
// defined. std::addressof handles types with overloaded operator&.
|
||||
template <typename C>
|
||||
explicit ArraySliceImpl(const C& v)
|
||||
: ArraySliceImplBase<const T>(ContainerData<T, C>::Get(std::addressof(v)),
|
||||
ContainerSize<C>::Get(std::addressof(v))) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MutableArraySliceImpl : public ArraySliceImplBase<T> {
|
||||
public:
|
||||
using ArraySliceImplBase<T>::ArraySliceImplBase;
|
||||
|
||||
template <typename C>
|
||||
using EnableIfConvertibleFrom =
|
||||
typename std::enable_if<ContainerMutableData<T, C>::HasGet() &&
|
||||
ContainerSize<C>::HasGet()>::type;
|
||||
|
||||
template <typename C>
|
||||
explicit MutableArraySliceImpl(C* v)
|
||||
: ArraySliceImplBase<T>(ContainerMutableData<T, C>::Get(v),
|
||||
ContainerSize<C>::Get(v)) {}
|
||||
};
|
||||
|
||||
} // namespace array_slice_internal
|
||||
} // namespace gtl
|
||||
} // namespace tensorflow
|
||||
|
||||
#endif // TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
|
@ -1,664 +0,0 @@
|
||||
/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/core/lib/gtl/array_slice.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||
#include "tensorflow/core/lib/gtl/stl_util.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/platform/test.h"
|
||||
#include "tensorflow/core/platform/types.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace gtl {
|
||||
namespace {
|
||||
|
||||
typedef ArraySlice<int> IntSlice;
|
||||
typedef ArraySlice<char> CharSlice;
|
||||
typedef MutableArraySlice<int> MutableIntSlice;
|
||||
typedef MutableArraySlice<char> MutableCharSlice;
|
||||
typedef std::vector<int> IntVec;
|
||||
|
||||
// Append 0..len-1 to *v
|
||||
template <typename Vector>
|
||||
static void Fill(Vector* v, int len, int offset = 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
v->push_back(i + offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestHelper(const IntSlice& vorig, const IntVec& vec) {
|
||||
IntSlice other; // To test the assignment return value.
|
||||
IntSlice v = other = vorig;
|
||||
const int len = vec.size();
|
||||
EXPECT_EQ(v.size(), vec.size());
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
EXPECT_EQ(v[i], vec[i]);
|
||||
EXPECT_EQ(v.at(i), vec[i]);
|
||||
}
|
||||
EXPECT_EQ(v.begin(), gtl::vector_as_array(&vec));
|
||||
|
||||
int counter = 0;
|
||||
for (IntSlice::iterator it = v.begin(); it != v.end(); ++it) {
|
||||
EXPECT_EQ(counter, *it);
|
||||
counter++;
|
||||
}
|
||||
EXPECT_EQ(counter, len);
|
||||
|
||||
counter = 0;
|
||||
for (IntSlice::const_iterator it = v.begin(); it != v.end(); ++it) {
|
||||
EXPECT_EQ(counter, *it);
|
||||
counter++;
|
||||
}
|
||||
EXPECT_EQ(counter, len);
|
||||
|
||||
if (len > 0) {
|
||||
EXPECT_EQ(0, v.front());
|
||||
EXPECT_EQ(len - 1, v.back());
|
||||
v.remove_suffix(1);
|
||||
EXPECT_EQ(len - 1, v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
EXPECT_EQ(i, v[i]);
|
||||
}
|
||||
if (len > 1) {
|
||||
v.remove_prefix(1);
|
||||
EXPECT_EQ(len - 2, v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
EXPECT_EQ(i + 1, v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The element access test that is applicable both when MutableArraySlice is
|
||||
// const and when it's not.
|
||||
template <class V>
|
||||
void MutableTestHelperTemplated(V v, int* ptr, const int len) {
|
||||
CHECK_EQ(v.size(), len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
EXPECT_EQ(ptr + i, &v[i]);
|
||||
EXPECT_EQ(ptr + i, &v.at(i));
|
||||
}
|
||||
EXPECT_EQ(ptr, v.begin());
|
||||
EXPECT_EQ(ptr + len, v.end());
|
||||
EXPECT_EQ(ptr, v.data());
|
||||
|
||||
int counter = 0;
|
||||
for (MutableIntSlice::const_iterator it = v.begin(); it != v.end(); ++it) {
|
||||
EXPECT_EQ(ptr + counter, &*it);
|
||||
counter++;
|
||||
}
|
||||
EXPECT_EQ(counter, len);
|
||||
|
||||
EXPECT_EQ(len, std::distance(v.rbegin(), v.rend()));
|
||||
|
||||
if (len > 0) {
|
||||
EXPECT_EQ(ptr, &v.front());
|
||||
EXPECT_EQ(ptr + len - 1, &v.back());
|
||||
EXPECT_EQ(ptr + len - 1, &*v.rbegin());
|
||||
EXPECT_EQ(ptr, &*(v.rend() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void MutableTestHelper(const MutableIntSlice& vorig, int* ptr,
|
||||
const int len) {
|
||||
// Test the data accessors both when the MutableArraySlice is declared const,
|
||||
// and when it is not.
|
||||
MutableTestHelperTemplated<const MutableIntSlice&>(vorig, ptr, len);
|
||||
MutableTestHelperTemplated<MutableIntSlice>(vorig, ptr, len);
|
||||
|
||||
MutableIntSlice other; // To test the assignment return value.
|
||||
MutableIntSlice v = other = vorig;
|
||||
EXPECT_EQ(ptr, v.data());
|
||||
|
||||
int counter = 0;
|
||||
for (MutableIntSlice::iterator it = v.begin(); it != v.end(); ++it) {
|
||||
EXPECT_EQ(ptr + counter, &*it);
|
||||
counter++;
|
||||
}
|
||||
EXPECT_EQ(counter, len);
|
||||
|
||||
if (len > 0) {
|
||||
// Test that elements are assignable.
|
||||
v[0] = 1;
|
||||
v.front() = 2;
|
||||
v.back() = 5;
|
||||
*v.data() = 4;
|
||||
std::fill(v.begin(), v.end(), 5);
|
||||
std::fill(v.rbegin(), v.rend(), 6);
|
||||
// Test size-changing methods.
|
||||
v.remove_suffix(1);
|
||||
EXPECT_EQ(len - 1, v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
EXPECT_EQ(ptr + i, &v[i]);
|
||||
}
|
||||
if (len > 1) {
|
||||
v.remove_prefix(1);
|
||||
EXPECT_EQ(len - 2, v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
EXPECT_EQ(ptr + i + 1, &v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Vector>
|
||||
static void TestImplicitConversion(const IntSlice& v, const Vector& vec) {
|
||||
EXPECT_EQ(v.size(), vec.size());
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
EXPECT_EQ(v[i], vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Vector>
|
||||
static void TestImplicitConversion(const CharSlice& v, const Vector& vec) {
|
||||
TestImplicitConversion(IntVec(v.begin(), v.end()), vec);
|
||||
}
|
||||
|
||||
static void TestImplicitConversion(const MutableIntSlice& v, const int* data,
|
||||
int size) {
|
||||
EXPECT_EQ(size, v.size());
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
EXPECT_EQ(data + i, &v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestImplicitConversion(const MutableCharSlice& v, const char* data,
|
||||
int size) {
|
||||
EXPECT_EQ(size, v.size());
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
EXPECT_EQ(data + i, &v[i]);
|
||||
}
|
||||
}
|
||||
// A struct supplying the data(), mutable_data() and size() methods, just like
|
||||
// e.g. proto2::RepeatedField.
|
||||
struct RepeatedField {
|
||||
std::vector<int> storage;
|
||||
const int* data() const { return storage.data(); }
|
||||
int* mutable_data() { return storage.data(); }
|
||||
int size() const { return storage.size(); }
|
||||
};
|
||||
|
||||
// A struct supplying the data() (both mutable and const versions) and
|
||||
// size(). It also supplies mutable_data() but we test that data() is selected
|
||||
// instead.
|
||||
struct ContainerWithOverloads {
|
||||
std::vector<int> storage;
|
||||
std::vector<int> wrong_storage;
|
||||
const int* data() const { return storage.data(); }
|
||||
int* data() { return storage.data(); }
|
||||
// MutableArraySlice should not call mutable_data(), preferring data()
|
||||
// instead.
|
||||
int* mutable_data() { return wrong_storage.data(); }
|
||||
int size() const { return storage.size(); }
|
||||
};
|
||||
|
||||
// A struct supplying data() and size() methods.
|
||||
struct ContainerWithShallowConstData {
|
||||
std::vector<int> storage;
|
||||
int* data() const { return const_cast<int*>(storage.data()); }
|
||||
int size() const { return storage.size(); }
|
||||
};
|
||||
|
||||
TEST(IntSlice, Simple) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec;
|
||||
Fill(&vec, len);
|
||||
TestHelper(IntSlice(vec), vec);
|
||||
TestHelper(IntSlice(vec.data(), vec.size()), vec);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, WithPosAndLen) {
|
||||
IntVec vec;
|
||||
Fill(&vec, 20);
|
||||
for (size_t len = 0; len < vec.size(); len++) {
|
||||
IntVec subvec(vec.begin(), vec.begin() + len);
|
||||
TestImplicitConversion(IntSlice(vec, 0, len), subvec);
|
||||
TestImplicitConversion(IntSlice(IntSlice(vec), 0, len), subvec);
|
||||
}
|
||||
EXPECT_EQ(0, IntSlice(vec, 0, 0).size());
|
||||
EXPECT_EQ(0, IntSlice(IntSlice(vec), 0, 0).size());
|
||||
TestImplicitConversion(IntSlice(vec, 0, IntSlice::npos), vec);
|
||||
}
|
||||
|
||||
TEST(IntSlice, Clear) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec;
|
||||
Fill(&vec, len);
|
||||
IntSlice v(vec);
|
||||
v.clear();
|
||||
EXPECT_EQ(0, v.size());
|
||||
EXPECT_EQ(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, Swap) {
|
||||
for (int l1 = 0; l1 < 20; l1++) {
|
||||
for (int l2 = 0; l2 < 20; l2++) {
|
||||
IntVec avec, bvec;
|
||||
Fill(&avec, l1);
|
||||
Fill(&bvec, l2, 100);
|
||||
IntSlice a(avec), b(bvec);
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
EXPECT_EQ(l1, b.size());
|
||||
EXPECT_EQ(l2, a.size());
|
||||
for (int i = 0; i < l1; i++) {
|
||||
EXPECT_EQ(i, b[i]);
|
||||
}
|
||||
for (int i = 0; i < l2; i++) {
|
||||
EXPECT_EQ(100 + i, a[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, ImplicitConversion) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec;
|
||||
Fill(&vec, len);
|
||||
IntSlice slice;
|
||||
slice = vec;
|
||||
TestImplicitConversion(vec, vec);
|
||||
TestImplicitConversion(slice, vec);
|
||||
TestImplicitConversion(IntSlice(vec.data(), vec.size()), vec);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, InlinedVectorConversion) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
InlinedVector<int, 4> inline_vec;
|
||||
for (int i = 0; i < len; i++) {
|
||||
inline_vec.push_back(i);
|
||||
}
|
||||
IntVec vec;
|
||||
Fill(&vec, len);
|
||||
IntSlice v = inline_vec; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(inline_vec, vec);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, StaticArrayConversion) {
|
||||
int array[20];
|
||||
IntVec vec;
|
||||
Fill(&vec, TF_ARRAYSIZE(array));
|
||||
std::copy(vec.begin(), vec.end(), array);
|
||||
IntSlice v = array; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(array, vec);
|
||||
}
|
||||
|
||||
TEST(IntSlice, StdArrayConversion) {
|
||||
std::array<int, 20> array;
|
||||
IntVec vec;
|
||||
Fill(&vec, array.size());
|
||||
std::copy(vec.begin(), vec.end(), array.begin());
|
||||
|
||||
// Check assignment.
|
||||
{
|
||||
IntSlice v = array;
|
||||
static_cast<void>(v);
|
||||
}
|
||||
|
||||
// Check sub-slice initialization.
|
||||
{
|
||||
IntSlice v = {array, 10, 15};
|
||||
static_cast<void>(v);
|
||||
}
|
||||
|
||||
TestImplicitConversion(array, vec);
|
||||
}
|
||||
|
||||
// Values according to the Fill function.
|
||||
static const int test_const_array[] = {0, 1, 2};
|
||||
|
||||
TEST(IntSlice, ConstStaticArrayConversion) {
|
||||
IntVec vec;
|
||||
Fill(&vec, TF_ARRAYSIZE(test_const_array));
|
||||
IntSlice v = test_const_array; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(test_const_array, vec);
|
||||
}
|
||||
|
||||
TEST(IntSlice, RepeatedFieldConversion) {
|
||||
RepeatedField repeated_field;
|
||||
IntVec vec;
|
||||
Fill(&vec, 20);
|
||||
repeated_field.storage = vec;
|
||||
IntSlice v = repeated_field; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(repeated_field, vec);
|
||||
}
|
||||
|
||||
TEST(IntSlice, ContainerWithOverloadsConversion) {
|
||||
ContainerWithOverloads container;
|
||||
Fill(&container.storage, 20);
|
||||
container.wrong_storage.resize(container.size());
|
||||
IntSlice v = container; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(container, container.storage);
|
||||
}
|
||||
|
||||
TEST(IntSlice, ContainerWithShallowConstDataConversion) {
|
||||
ContainerWithShallowConstData container;
|
||||
Fill(&container.storage, 20);
|
||||
IntSlice v = container; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(container, container.storage);
|
||||
}
|
||||
|
||||
TEST(IntSlice, MutableIntSliceConversion) {
|
||||
IntVec vec(20);
|
||||
IntSlice slice = MutableIntSlice(&vec);
|
||||
EXPECT_EQ(vec.size(), slice.size());
|
||||
EXPECT_EQ(vec.data(), slice.data());
|
||||
}
|
||||
|
||||
TEST(IntSlice, Equality) {
|
||||
IntVec vec1(20);
|
||||
IntVec vec2(20);
|
||||
// These two slices are from different vectors, but have the same
|
||||
// size and have the same elements (right now). They should
|
||||
// compare equal.
|
||||
const IntSlice from1(vec1);
|
||||
const IntSlice from2(vec2);
|
||||
EXPECT_EQ(from1, from1);
|
||||
EXPECT_EQ(from1, from2);
|
||||
|
||||
// This verifies that MutableArraySlices can be compared freely with
|
||||
// ArraySlices.
|
||||
const MutableIntSlice mutable_from1(&vec1);
|
||||
const MutableIntSlice mutable_from2(&vec2);
|
||||
EXPECT_EQ(from1, mutable_from1);
|
||||
EXPECT_EQ(mutable_from1, from1);
|
||||
EXPECT_EQ(mutable_from1, mutable_from2);
|
||||
EXPECT_EQ(mutable_from2, mutable_from1);
|
||||
|
||||
// With a different size, the array slices should not be equal.
|
||||
EXPECT_NE(from1, IntSlice(from1, 0, from1.size() - 1));
|
||||
|
||||
// With different contents, the array slices should not be equal.
|
||||
++vec2.back();
|
||||
EXPECT_NE(from1, from2);
|
||||
}
|
||||
|
||||
// Compile-asserts that the argument has the expected type.
|
||||
template <typename Expected, typename T>
|
||||
void CheckType(const T& value) {
|
||||
::testing::StaticAssertTypeEq<Expected, T>();
|
||||
}
|
||||
|
||||
TEST(IntSlice, ExposesContainerTypesAndConsts) {
|
||||
IntSlice slice;
|
||||
const IntSlice const_slice;
|
||||
CheckType<IntSlice::iterator>(slice.begin());
|
||||
CheckType<IntSlice::const_iterator>(const_slice.end());
|
||||
CheckType<IntSlice::const_reverse_iterator>(const_slice.rbegin());
|
||||
CheckType<IntSlice::reverse_iterator>(slice.rend());
|
||||
::testing::StaticAssertTypeEq<int, IntSlice::value_type>();
|
||||
::testing::StaticAssertTypeEq<const int*, IntSlice::pointer>();
|
||||
::testing::StaticAssertTypeEq<const int&, IntSlice::const_reference>();
|
||||
EXPECT_EQ(static_cast<IntSlice::size_type>(-1), IntSlice::npos);
|
||||
}
|
||||
|
||||
void TestEmpty(IntSlice slice) { ASSERT_TRUE(slice.empty()); }
|
||||
|
||||
void TestRange(IntSlice slice, int from, int to) {
|
||||
ASSERT_EQ(to - from + 1, slice.size());
|
||||
for (size_t i = 0; i < slice.size(); ++i) {
|
||||
EXPECT_EQ(from + i, slice[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntSlice, InitializerListConversion) {
|
||||
TestEmpty({});
|
||||
TestRange({1}, 1, 1);
|
||||
TestRange({10, 11, 12, 13}, 10, 13);
|
||||
}
|
||||
|
||||
TEST(CharSlice, StringConversion) {
|
||||
IntVec vec;
|
||||
Fill(&vec, 20);
|
||||
string str(vec.begin(), vec.end());
|
||||
CharSlice v = str; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(str, vec);
|
||||
}
|
||||
|
||||
TEST(IntPtrSlice, ConstConversion) {
|
||||
int one = 1;
|
||||
int two = 2;
|
||||
std::vector<int*> vec;
|
||||
vec.push_back(&one);
|
||||
vec.push_back(&two);
|
||||
ArraySlice<const int*> v = vec;
|
||||
ASSERT_EQ(2, v.size());
|
||||
EXPECT_EQ(&one, v[0]);
|
||||
EXPECT_EQ(&two, v[1]);
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, Simple) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec(len);
|
||||
MutableTestHelper(MutableIntSlice(&vec), vec.data(), len);
|
||||
MutableTestHelper(MutableIntSlice(vec.data(), vec.size()), vec.data(), len);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, WithPosAndLen) {
|
||||
IntVec vec(20);
|
||||
for (size_t len = 0; len < vec.size(); len++) {
|
||||
TestImplicitConversion(MutableIntSlice(&vec, 0, len), vec.data(), len);
|
||||
TestImplicitConversion(MutableIntSlice(MutableIntSlice(&vec), 0, len),
|
||||
vec.data(), len);
|
||||
}
|
||||
EXPECT_EQ(0, MutableIntSlice(&vec, 0, 0).size());
|
||||
EXPECT_EQ(0, MutableIntSlice(MutableIntSlice(&vec), 0, 0).size());
|
||||
TestImplicitConversion(MutableIntSlice(&vec, 0, MutableIntSlice::npos),
|
||||
vec.data(), vec.size());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, Clear) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec(len);
|
||||
MutableIntSlice v(&vec);
|
||||
v.clear();
|
||||
EXPECT_EQ(0, v.size());
|
||||
EXPECT_EQ(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, Swap) {
|
||||
for (int l1 = 0; l1 < 20; l1++) {
|
||||
for (int l2 = 0; l2 < 20; l2++) {
|
||||
IntVec avec(l1), bvec(l2);
|
||||
MutableIntSlice a(&avec), b(&bvec);
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
EXPECT_EQ(l1, b.size());
|
||||
EXPECT_EQ(l2, a.size());
|
||||
for (int i = 0; i < l1; i++) {
|
||||
EXPECT_EQ(&avec[i], &b[i]);
|
||||
}
|
||||
for (int i = 0; i < l2; i++) {
|
||||
EXPECT_EQ(&bvec[i], &a[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, ImplicitConversion) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
IntVec vec(len);
|
||||
MutableIntSlice slice;
|
||||
slice = &vec;
|
||||
TestImplicitConversion(&vec, vec.data(), len);
|
||||
TestImplicitConversion(slice, vec.data(), len);
|
||||
TestImplicitConversion(MutableIntSlice(vec.data(), vec.size()), vec.data(),
|
||||
len);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, InlinedVectorConversion) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
InlinedVector<int, 4> inline_vec;
|
||||
for (int i = 0; i < len; i++) {
|
||||
inline_vec.push_back(i);
|
||||
}
|
||||
MutableIntSlice v = &inline_vec; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(&inline_vec, inline_vec.data(), inline_vec.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, StaticArrayConversion) {
|
||||
int array[20];
|
||||
MutableIntSlice v = array; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(array, array, TF_ARRAYSIZE(array));
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, StdArrayConversion) {
|
||||
std::array<int, 20> array;
|
||||
|
||||
// Check assignment.
|
||||
{
|
||||
MutableIntSlice v = &array;
|
||||
static_cast<void>(v);
|
||||
}
|
||||
|
||||
// Check sub-slice initialization.
|
||||
{
|
||||
MutableIntSlice v = {&array, 10, 15};
|
||||
static_cast<void>(v);
|
||||
}
|
||||
|
||||
TestImplicitConversion(&array, &array[0], array.size());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, RepeatedFieldConversion) {
|
||||
RepeatedField repeated_field;
|
||||
Fill(&repeated_field.storage, 20);
|
||||
MutableIntSlice v = &repeated_field; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(&repeated_field, repeated_field.storage.data(),
|
||||
repeated_field.storage.size());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, ContainerWithOverloadsConversion) {
|
||||
ContainerWithOverloads container;
|
||||
Fill(&container.storage, 20);
|
||||
container.wrong_storage.resize(container.size());
|
||||
MutableIntSlice v = &container; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(&container, container.storage.data(),
|
||||
container.storage.size());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, ContainerWithShallowConstDataConversion) {
|
||||
ContainerWithShallowConstData container;
|
||||
Fill(&container.storage, 20);
|
||||
MutableIntSlice v = &container; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(&container, container.storage.data(),
|
||||
container.storage.size());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, TypedefsAndConstants) {
|
||||
::testing::StaticAssertTypeEq<int, MutableIntSlice::value_type>();
|
||||
::testing::StaticAssertTypeEq<int*, MutableIntSlice::pointer>();
|
||||
::testing::StaticAssertTypeEq<const int*, MutableIntSlice::const_pointer>();
|
||||
::testing::StaticAssertTypeEq<int&, MutableIntSlice::reference>();
|
||||
::testing::StaticAssertTypeEq<const int&, MutableIntSlice::const_reference>();
|
||||
|
||||
EXPECT_EQ(static_cast<MutableIntSlice::size_type>(-1), MutableIntSlice::npos);
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, IteratorsAndReferences) {
|
||||
auto accept_pointer = [](int* x) {};
|
||||
auto accept_reference = [](int& x) {};
|
||||
auto accept_iterator = [](MutableIntSlice::iterator x) {};
|
||||
auto accept_reverse_iterator = [](MutableIntSlice::reverse_iterator x) {};
|
||||
|
||||
int a[1];
|
||||
MutableIntSlice s = a;
|
||||
|
||||
accept_pointer(s.data());
|
||||
accept_iterator(s.begin());
|
||||
accept_iterator(s.end());
|
||||
accept_reverse_iterator(s.rbegin());
|
||||
accept_reverse_iterator(s.rend());
|
||||
|
||||
accept_reference(s[0]);
|
||||
accept_reference(s.at(0));
|
||||
accept_reference(s.front());
|
||||
accept_reference(s.back());
|
||||
}
|
||||
|
||||
TEST(MutableIntSlice, IteratorsAndReferences_Const) {
|
||||
auto accept_pointer = [](int* x) {};
|
||||
auto accept_reference = [](int& x) {};
|
||||
auto accept_iterator = [](MutableIntSlice::iterator x) {};
|
||||
auto accept_reverse_iterator = [](MutableIntSlice::reverse_iterator x) {};
|
||||
|
||||
int a[1];
|
||||
const MutableIntSlice s = a;
|
||||
|
||||
accept_pointer(s.data());
|
||||
accept_iterator(s.begin());
|
||||
accept_iterator(s.end());
|
||||
accept_reverse_iterator(s.rbegin());
|
||||
accept_reverse_iterator(s.rend());
|
||||
|
||||
accept_reference(s[0]);
|
||||
accept_reference(s.at(0));
|
||||
accept_reference(s.front());
|
||||
accept_reference(s.back());
|
||||
}
|
||||
|
||||
bool TestMutableOverload(MutableIntSlice slice) { return false; }
|
||||
|
||||
bool TestMutableOverload(MutableCharSlice slice) { return true; }
|
||||
|
||||
TEST(MutableCharSlice, StringConversion) {
|
||||
for (int len = 0; len < 20; len++) {
|
||||
string str(len, '\0');
|
||||
MutableCharSlice v = &str; // Test assignment
|
||||
static_cast<void>(v);
|
||||
TestImplicitConversion(v, str.data(), str.size());
|
||||
}
|
||||
// Verify that only the correct overload is feasible. Note that this would
|
||||
// fail if the string ctor was declared simply as MutableArraySlice(string*),
|
||||
// since in that case both overloads would be feasible.
|
||||
string str;
|
||||
EXPECT_TRUE(TestMutableOverload(&str));
|
||||
|
||||
// Avoid warning "unused function 'TestMutableOverload'"
|
||||
int a[1];
|
||||
EXPECT_FALSE(TestMutableOverload(a));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace gtl
|
||||
} // namespace tensorflow
|
@ -623,7 +623,10 @@ def tf_additional_lib_defines():
|
||||
|
||||
def tf_additional_lib_deps():
|
||||
"""Additional dependencies needed to build TF libraries."""
|
||||
return ["@com_google_absl//absl/base:base"] + if_static(
|
||||
return [
|
||||
"@com_google_absl//absl/base:base",
|
||||
"@com_google_absl//absl/types:span",
|
||||
] + if_static(
|
||||
["@nsync//:nsync_cpp"],
|
||||
["@nsync//:nsync_headers"],
|
||||
) + select({
|
||||
|
@ -3894,7 +3894,7 @@ bool CudnnSupport::DoDepthConcatenate(
|
||||
for (size_t i = 0; i < input_data.size(); ++i) {
|
||||
const auto& dimensions = input_dimensions[i];
|
||||
tmp.resize(dimensions.ElementCount());
|
||||
stream->ThenMemcpyD2H<float>(*input_data[i], &tmp);
|
||||
stream->ThenMemcpyD2H<float>(*input_data[i], absl::MakeSpan(tmp));
|
||||
port::Status block_status = stream->BlockHostUntilDone();
|
||||
if (!block_status.ok()) {
|
||||
LOG(ERROR) << "BlockHostUntilDone failed: " << block_status;
|
||||
|
Loading…
Reference in New Issue
Block a user