any.c++ 7.66 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
Kenton Varda's avatar
Kenton Varda committed
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
Kenton Varda's avatar
Kenton Varda committed
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
Kenton Varda's avatar
Kenton Varda committed
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Kenton Varda's avatar
Kenton Varda committed
21

22
#include "any.h"
23

24 25
#include <kj/debug.h>

26
#if !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
27
#include "capability.h"
28
#endif  // !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
29 30 31

namespace capnp {

32 33
#if !CAPNP_LITE

34
kj::Own<ClientHook> PipelineHook::getPipelinedCap(kj::Array<PipelineOp>&& ops) {
35 36 37
  return getPipelinedCap(ops.asPtr());
}

38
kj::Own<ClientHook> AnyPointer::Reader::getPipelinedCap(
39
    kj::ArrayPtr<const PipelineOp> ops) const {
Kenton Varda's avatar
Kenton Varda committed
40 41 42 43
  _::PointerReader pointer = reader;

  for (auto& op: ops) {
    switch (op.type) {
44 45 46
      case PipelineOp::Type::NOOP:
        break;

Kenton Varda's avatar
Kenton Varda committed
47
      case PipelineOp::Type::GET_POINTER_FIELD:
48
        pointer = pointer.getStruct(nullptr).getPointerField(bounded(op.pointerIndex) * POINTERS);
Kenton Varda's avatar
Kenton Varda committed
49 50 51 52 53 54 55
        break;
    }
  }

  return pointer.getCapability();
}

56
AnyPointer::Pipeline AnyPointer::Pipeline::noop() {
57 58 59 60 61 62 63
  auto newOps = kj::heapArray<PipelineOp>(ops.size());
  for (auto i: kj::indices(ops)) {
    newOps[i] = ops[i];
  }
  return Pipeline(hook->addRef(), kj::mv(newOps));
}

64
AnyPointer::Pipeline AnyPointer::Pipeline::getPointerField(uint16_t pointerIndex) {
65 66 67 68 69 70 71 72 73 74 75
  auto newOps = kj::heapArray<PipelineOp>(ops.size() + 1);
  for (auto i: kj::indices(ops)) {
    newOps[i] = ops[i];
  }
  auto& newOp = newOps[ops.size()];
  newOp.type = PipelineOp::GET_POINTER_FIELD;
  newOp.pointerIndex = pointerIndex;

  return Pipeline(hook->addRef(), kj::mv(newOps));
}

76
kj::Own<ClientHook> AnyPointer::Pipeline::asCap() {
77 78 79
  return hook->getPipelinedCap(ops);
}

80 81
#endif  // !CAPNP_LITE

82
Equality AnyStruct::Reader::equals(AnyStruct::Reader right) {
83
  auto dataL = getDataSection();
84 85 86 87 88 89 90 91 92 93 94 95
  size_t dataSizeL = dataL.size();
  while(dataSizeL > 0 && dataL[dataSizeL - 1] == 0) {
    -- dataSizeL;
  }

  auto dataR = right.getDataSection();
  size_t dataSizeR = dataR.size();
  while(dataSizeR > 0 && dataR[dataSizeR - 1] == 0) {
    -- dataSizeR;
  }

  if(dataSizeL != dataSizeR) {
96
    return Equality::NOT_EQUAL;
97 98
  }

99
  if(0 != memcmp(dataL.begin(), dataR.begin(), dataSizeL)) {
100
    return Equality::NOT_EQUAL;
101 102
  }

103
  auto ptrsL = getPointerSection();
104 105 106 107 108
  size_t ptrsSizeL = ptrsL.size();
  while (ptrsSizeL > 0 && ptrsL[ptrsSizeL - 1].isNull()) {
    -- ptrsSizeL;
  }

109
  auto ptrsR = right.getPointerSection();
110 111 112 113 114 115 116 117
  size_t ptrsSizeR = ptrsR.size();
  while (ptrsSizeR > 0 && ptrsR[ptrsSizeR - 1].isNull()) {
    -- ptrsSizeR;
  }

  if(ptrsSizeL != ptrsSizeR) {
    return Equality::NOT_EQUAL;
  }
118 119 120

  size_t i = 0;

121
  auto eqResult = Equality::EQUAL;
122
  for (; i < ptrsSizeL; i++) {
123 124
    auto l = ptrsL[i];
    auto r = ptrsR[i];
125
    switch(l.equals(r)) {
126
      case Equality::EQUAL:
127
        break;
128 129 130 131
      case Equality::NOT_EQUAL:
        return Equality::NOT_EQUAL;
      case Equality::UNKNOWN_CONTAINS_CAPS:
        eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
132 133 134
        break;
      default:
        KJ_UNREACHABLE;
135 136 137
    }
  }

138
  return eqResult;
139 140
}

141
kj::StringPtr KJ_STRINGIFY(Equality res) {
142
  switch(res) {
143
    case Equality::NOT_EQUAL:
144
      return "NOT_EQUAL";
145
    case Equality::EQUAL:
146
      return "EQUAL";
147
    case Equality::UNKNOWN_CONTAINS_CAPS:
148
      return "UNKNOWN_CONTAINS_CAPS";
149
  }
150
  KJ_UNREACHABLE;
151 152
}

153
Equality AnyList::Reader::equals(AnyList::Reader right) {
154
  if(size() != right.size()) {
155
    return Equality::NOT_EQUAL;
156
  }
157 158 159 160 161

  if (getElementSize() != right.getElementSize()) {
    return Equality::NOT_EQUAL;
  }

162
  auto eqResult = Equality::EQUAL;
163
  switch(getElementSize()) {
164 165 166 167 168
    case ElementSize::VOID:
    case ElementSize::BIT:
    case ElementSize::BYTE:
    case ElementSize::TWO_BYTES:
    case ElementSize::FOUR_BYTES:
169 170 171 172 173 174 175 176 177
    case ElementSize::EIGHT_BYTES: {
      size_t cmpSize = getRawBytes().size();

      if (getElementSize() == ElementSize::BIT && size() % 8 != 0) {
        // The list does not end on a byte boundary. We need special handling for the final
        // byte because we only care about the bits that are actually elements of the list.

        uint8_t mask = (1 << (size() % 8)) - 1; // lowest size() bits set
        if ((getRawBytes()[cmpSize - 1] & mask) != (right.getRawBytes()[cmpSize - 1] & mask)) {
178
          return Equality::NOT_EQUAL;
179
        }
180 181 182 183 184
        cmpSize -= 1;
      }

      if (memcmp(getRawBytes().begin(), right.getRawBytes().begin(), cmpSize) == 0) {
        return Equality::EQUAL;
185
      } else {
186
        return Equality::NOT_EQUAL;
187
      }
188
    }
189 190 191 192 193 194
    case ElementSize::POINTER:
    case ElementSize::INLINE_COMPOSITE: {
      auto llist = as<List<AnyStruct>>();
      auto rlist = right.as<List<AnyStruct>>();
      for(size_t i = 0; i < size(); i++) {
        switch(llist[i].equals(rlist[i])) {
195
          case Equality::EQUAL:
196
            break;
197 198 199 200
          case Equality::NOT_EQUAL:
            return Equality::NOT_EQUAL;
          case Equality::UNKNOWN_CONTAINS_CAPS:
            eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
201 202 203
            break;
          default:
            KJ_UNREACHABLE;
204
        }
205
      }
206
      return eqResult;
207 208
    }
  }
209
  KJ_UNREACHABLE;
210 211
}

212
Equality AnyPointer::Reader::equals(AnyPointer::Reader right) {
213
  if(getPointerType() != right.getPointerType()) {
214
    return Equality::NOT_EQUAL;
215
  }
216 217
  switch(getPointerType()) {
    case PointerType::NULL_:
218
      return Equality::EQUAL;
219
    case PointerType::STRUCT:
220
      return getAs<AnyStruct>().equals(right.getAs<AnyStruct>());
221
    case PointerType::LIST:
222
      return getAs<AnyList>().equals(right.getAs<AnyList>());
223
    case PointerType::CAPABILITY:
224
      return Equality::UNKNOWN_CONTAINS_CAPS;
225
  }
226 227
  // There aren't currently any other types of pointers
  KJ_UNREACHABLE;
228 229
}

230
bool AnyPointer::Reader::operator==(AnyPointer::Reader right) {
231
  switch(equals(right)) {
232
    case Equality::EQUAL:
233
      return true;
234
    case Equality::NOT_EQUAL:
235
      return false;
236
    case Equality::UNKNOWN_CONTAINS_CAPS:
237 238
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
239
  }
240
  KJ_UNREACHABLE;
241 242
}

243
bool AnyStruct::Reader::operator==(AnyStruct::Reader right) {
244
  switch(equals(right)) {
245
    case Equality::EQUAL:
246
      return true;
247
    case Equality::NOT_EQUAL:
248
      return false;
249
    case Equality::UNKNOWN_CONTAINS_CAPS:
250 251
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
252
  }
253
  KJ_UNREACHABLE;
254 255
}

256
bool AnyList::Reader::operator==(AnyList::Reader right) {
257
  switch(equals(right)) {
258
    case Equality::EQUAL:
259
      return true;
260
    case Equality::NOT_EQUAL:
261
      return false;
262
    case Equality::UNKNOWN_CONTAINS_CAPS:
263 264
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
265
  }
266
  KJ_UNREACHABLE;
267 268
}

Kenton Varda's avatar
Kenton Varda committed
269
}  // namespace capnp