summaryrefslogtreecommitdiffstats
path: root/js/public/ValueArray.h
blob: 0d520fb9b624f3fe4144bfba7b0298d0a3c8061e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/** GC-safe representations of consecutive JS::Value in memory. */

#ifndef js_ValueArray_h
#define js_ValueArray_h

#include "mozilla/Assertions.h"  // MOZ_ASSERT
#include "mozilla/Attributes.h"  // MOZ_IMPLICIT, MOZ_RAII

#include <stdint.h>  // size_t

#include "js/CallArgs.h"    // JS::CallArgs
#include "js/GCVector.h"    // JS::RootedVector
#include "js/RootingAPI.h"  // JS::AutoGCRooter, JS::{,Mutable}Handle
#include "js/Value.h"       // JS::Value

namespace js {
JS_PUBLIC_API void TraceValueArray(JSTracer* trc, size_t length,
                                   JS::Value* elements);
}  // namespace js

namespace JS {

/* A fixed-size array of values, for use inside Rooted<>. */
template <size_t N>
struct ValueArray {
  Value elements[N];
  void trace(JSTracer* trc) { js::TraceValueArray(trc, N, elements); }
};

/** RootedValueArray roots an internal fixed-size array of Values. */
template <size_t N>
using RootedValueArray = Rooted<ValueArray<N>>;

/**
 * A generic handle to an array of rooted values.
 *
 * The rooted array refernced can take several forms, therfore this is not the
 * same as Handle<js::ValueArray>.
 */
class HandleValueArray {
  const size_t length_;
  const Value* const elements_;

  HandleValueArray(size_t len, const Value* elements)
      : length_(len), elements_(elements) {}

 public:
  explicit HandleValueArray(Handle<Value> value)
      : length_(1), elements_(value.address()) {}

  MOZ_IMPLICIT HandleValueArray(const RootedVector<Value>& values)
      : length_(values.length()), elements_(values.begin()) {}

  template <size_t N>
  MOZ_IMPLICIT HandleValueArray(const RootedValueArray<N>& values)
      : length_(N), elements_(values.begin()) {}

  /** CallArgs must already be rooted somewhere up the stack. */
  MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args)
      : length_(args.length()), elements_(args.array()) {}

  /** Use with care! Only call this if the data is guaranteed to be marked. */
  static HandleValueArray fromMarkedLocation(size_t len,
                                             const Value* elements) {
    return HandleValueArray(len, elements);
  }

  static HandleValueArray subarray(const HandleValueArray& values,
                                   size_t startIndex, size_t len) {
    MOZ_ASSERT(startIndex + len <= values.length());
    return HandleValueArray(len, values.begin() + startIndex);
  }

  static HandleValueArray empty() { return HandleValueArray(0, nullptr); }

  size_t length() const { return length_; }
  const Value* begin() const { return elements_; }

  Handle<Value> operator[](size_t i) const {
    MOZ_ASSERT(i < length_);
    return Handle<Value>::fromMarkedLocation(&elements_[i]);
  }
};

}  // namespace JS

namespace js {

template <size_t N, typename Container>
class WrappedPtrOperations<JS::ValueArray<N>, Container> {
  const JS::ValueArray<N>& array() const {
    return static_cast<const Container*>(this)->get();
  }

 public:
  size_t length() const { return N; }
  const JS::Value* begin() const { return array().elements; }

  JS::HandleValue operator[](size_t i) const {
    MOZ_ASSERT(i < N);
    return JS::HandleValue::fromMarkedLocation(&array().elements[i]);
  }
};

template <size_t N, typename Container>
class MutableWrappedPtrOperations<JS::ValueArray<N>, Container>
    : public WrappedPtrOperations<JS::ValueArray<N>, Container> {
  using Base = WrappedPtrOperations<JS::ValueArray<N>, Container>;
  JS::ValueArray<N>& array() { return static_cast<Container*>(this)->get(); }

 public:
  using Base::begin;
  JS::Value* begin() { return array().elements; }

  using Base::operator[];
  JS::MutableHandleValue operator[](size_t i) {
    MOZ_ASSERT(i < N);
    return JS::MutableHandleValue::fromMarkedLocation(&array().elements[i]);
  }
};

}  // namespace js

#endif  // js_ValueArray_h