any.c++ 7.39 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
  auto ptrsR = right.getPointerSection();

  size_t i = 0;

108
  auto eqResult = Equality::EQUAL;
109 110 111
  for(; i < kj::min(ptrsL.size(), ptrsR.size()); i++) {
    auto l = ptrsL[i];
    auto r = ptrsR[i];
112
    switch(l.equals(r)) {
113
      case Equality::EQUAL:
114
        break;
115 116 117 118
      case Equality::NOT_EQUAL:
        return Equality::NOT_EQUAL;
      case Equality::UNKNOWN_CONTAINS_CAPS:
        eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
119 120 121
        break;
      default:
        KJ_UNREACHABLE;
122 123 124
    }
  }

125
  return eqResult;
126 127
}

128
kj::StringPtr KJ_STRINGIFY(Equality res) {
129
  switch(res) {
130
    case Equality::NOT_EQUAL:
131
      return "NOT_EQUAL";
132
    case Equality::EQUAL:
133
      return "EQUAL";
134
    case Equality::UNKNOWN_CONTAINS_CAPS:
135
      return "UNKNOWN_CONTAINS_CAPS";
136
  }
137
  KJ_UNREACHABLE;
138 139
}

140
Equality AnyList::Reader::equals(AnyList::Reader right) {
141
  if(size() != right.size()) {
142
    return Equality::NOT_EQUAL;
143
  }
144 145 146 147 148

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

149
  auto eqResult = Equality::EQUAL;
150
  switch(getElementSize()) {
151 152 153 154 155
    case ElementSize::VOID:
    case ElementSize::BIT:
    case ElementSize::BYTE:
    case ElementSize::TWO_BYTES:
    case ElementSize::FOUR_BYTES:
156 157 158 159 160 161 162 163 164
    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)) {
165
          return Equality::NOT_EQUAL;
166
        }
167 168 169 170 171
        cmpSize -= 1;
      }

      if (memcmp(getRawBytes().begin(), right.getRawBytes().begin(), cmpSize) == 0) {
        return Equality::EQUAL;
172
      } else {
173
        return Equality::NOT_EQUAL;
174
      }
175
    }
176 177 178 179 180 181
    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])) {
182
          case Equality::EQUAL:
183
            break;
184 185 186 187
          case Equality::NOT_EQUAL:
            return Equality::NOT_EQUAL;
          case Equality::UNKNOWN_CONTAINS_CAPS:
            eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
188 189 190
            break;
          default:
            KJ_UNREACHABLE;
191
        }
192
      }
193
      return eqResult;
194 195
    }
  }
196
  KJ_UNREACHABLE;
197 198
}

199
Equality AnyPointer::Reader::equals(AnyPointer::Reader right) {
200
  if(getPointerType() != right.getPointerType()) {
201
    return Equality::NOT_EQUAL;
202
  }
203 204
  switch(getPointerType()) {
    case PointerType::NULL_:
205
      return Equality::EQUAL;
206
    case PointerType::STRUCT:
207
      return getAs<AnyStruct>().equals(right.getAs<AnyStruct>());
208
    case PointerType::LIST:
209
      return getAs<AnyList>().equals(right.getAs<AnyList>());
210
    case PointerType::CAPABILITY:
211
      return Equality::UNKNOWN_CONTAINS_CAPS;
212
  }
213 214
  // There aren't currently any other types of pointers
  KJ_UNREACHABLE;
215 216
}

217
bool AnyPointer::Reader::operator==(AnyPointer::Reader right) {
218
  switch(equals(right)) {
219
    case Equality::EQUAL:
220
      return true;
221
    case Equality::NOT_EQUAL:
222
      return false;
223
    case Equality::UNKNOWN_CONTAINS_CAPS:
224 225
      KJ_FAIL_REQUIRE(
        "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
226
  }
227
  KJ_UNREACHABLE;
228 229
}

230
bool AnyStruct::Reader::operator==(AnyStruct::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 AnyList::Reader::operator==(AnyList::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
}

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