libgolang.h 27.5 KB
Newer Older
1 2 3
#ifndef _NXD_LIBGOLANG_H
#define _NXD_LIBGOLANG_H

4
// Copyright (C) 2018-2024  Nexedi SA and Contributors.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//                          Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.

// Library Libgolang provides Go-like features for C and C++.
//
25
// Library Libgolang provides goroutines, channels with Go semantic and other
Kirill Smelkov's avatar
Kirill Smelkov committed
26
// accompanying features. The library consists of high-level type-safe C++ API,
27 28
// and low-level unsafe C API. The low-level C API was inspired by Libtask[1]
// and Plan9/Libthread[2].
29 30 31 32 33 34 35 36 37
//
// The primary motivation for Libgolang is to serve as runtime for golang.pyx -
// - Cython part of Pygolang project. However Libgolang is independent of
// Python and should be possible to use in standalone C/C++ projects.
//
// Brief description of Libgolang API follows:
//
// C++-level API
//
Kirill Smelkov's avatar
Kirill Smelkov committed
38
//  - `go` spawns new task.
39 40
//  - `chan<T>`, and `select` provide channels with Go semantic and automatic
//    lifetime management.
41
//  - `defer` schedules cleanup.
42
//  - `error` is the interface that represents errors.
43 44 45 46
//  - `panic` throws exception that represent C-level panic.
//
// For example:
//
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
//      chan<int> ch = makechan<int>(); // create new channel
//      go(worker, ch, 1);              // spawn worker(chan<int>, int)
//      ch.send(1)
//      j = ch.recv()
//
//      _ = select({
//          _default,       // 0
//          ch.sends(&i),   // 1
//          ch.recvs(&j),   // 2
//      });
//      if (_ == 0)
//          // default case selected
//      if (_ == 1)
//          // case 1 selected: i sent to ch
//      if (_ == 2)
//          // case 2 selected: j received from ch
Kirill Smelkov's avatar
Kirill Smelkov committed
63
//
64 65 66 67
//      defer([]() {
//          printf("leaving...\n");
//      });
//
68 69 70 71
//      if (<bug condition>)
//          panic("bug");
//
//
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
// Memory management
//
// C++-level API provides limited support for automatic memory management:
//
//  - `refptr` and `object` provide way to manage objects lifetime automatically.
//  - `newref` and `adoptref` can be used to convert raw pointer into refptr<T>.
//  - `global` should be used for global refptr pointers.
//
// For example:
//
//      // MyObject is defined via 2 classes: _MyObject + MyObject
//      typedef refptr<struct _MyObject> MyObject;
//      struct _MyObject : object {
//          int x;
//
//          // don't new - create only view NewMyObject()
//      private:
//          _MyObject();
//          ~_MyObject();
//          friend MyObject NewMyObject(int x);
//      public:
//          void decref();
//
//          // MyObject API
//          void do_something() {
//              ...
//          }
//      };
//
//      MyObject NewMyObject(int x) {
//          MyObject obj = adoptref(new _MyObject());
//          obj->x = x;
//          return obj;
//      }
//
//      _MyObject::_MyObject()  {}
//      _MyObject::~_MyObject() {}
//      void _MyObject::decref() {
//          if (__decref())
//              delete this;
//      }
//
//      ...
//
//      global<MyObject> gobj = NewMyObject(1); // global object instance
//
//      void myfunc() {
//          MyObject obj = NewMyObject(123);
//          ...
//          obj->x;                 // use data field of the object
//          obj->do_something();    // call method of the object
//          ...
//          // obj is automatically deallocated on function exit
//      }
//
//
128 129 130 131 132 133 134 135 136 137 138
// Interfaces
//
// C++-level API provides limited support for interfaces:
//
//  - `interface` is empty interface a-la interface{} in Go.
//  - `error` is the interface describing errors.
//
// There is no support for at-runtime interface construction for an object:
// a class must inherit from all interfaces that it wants to implement.
//
//
139
// C-level API
Kirill Smelkov's avatar
Kirill Smelkov committed
140
//
Kirill Smelkov's avatar
Kirill Smelkov committed
141
//  - `_taskgo` spawns new task.
142 143 144 145
//  - `_makechan` creates raw channel with Go semantic.
//  - `_chanxincref` and `_chanxdecref` manage channel lifetime.
//  - `_chansend` and `_chanrecv` send/receive over raw channel.
//  - `_chanselect`, `_selsend`, `_selrecv`, ... provide raw select functionality.
Kirill Smelkov's avatar
Kirill Smelkov committed
146 147
//
//
Kirill Smelkov's avatar
Kirill Smelkov committed
148 149 150 151 152 153 154 155 156 157 158 159 160
// Runtimes
//
// Libgolang, before being used, must be initialized with particular runtime
// plugin, which tailors Libgolang to particular execution environment. See
// `_libgolang_init` and `_libgolang_runtime_ops` for description of a runtime.
//
// Pygolang - the parent project of Libgolang - comes with two Libgolang runtimes:
//
//  - "thread" - a runtime that is based on OS threads, and
//  - "gevent" - a runtime that is based on greenlet and gevent.
//
// Once again, Libgolang itself is independent from Python, and other runtimes
// are possible.
161 162
//
//
163 164
// Additional packages
//
Kirill Smelkov's avatar
Kirill Smelkov committed
165
// Libgolang, besides goroutines and channels, provides additional packages
166 167 168
// that mirror Go analogs. See for example golang/time.h, golang/sync.h, etc.
//
//
169 170
// [1] Libtask: a Coroutine Library for C and Unix. https://swtch.com/libtask.
// [2] http://9p.io/magic/man2html/2/thread.
171

172 173
#include "golang/runtime/platform.h"

174 175 176 177
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

Kirill Smelkov's avatar
Kirill Smelkov committed
178 179 180
#include <sys/types.h>
#include <sys/stat.h>

181
#include <fcntl.h>
182
#ifdef LIBGOLANG_CC_msc // no mode_t on msvc
183 184 185 186
typedef int mode_t;
#endif


187
// DSO symbols visibility (based on https://gcc.gnu.org/wiki/Visibility)
188
#ifdef LIBGOLANG_OS_windows
189 190
  #define LIBGOLANG_DSO_EXPORT __declspec(dllexport)
  #define LIBGOLANG_DSO_IMPORT __declspec(dllimport)
191
#else
192 193 194 195 196 197 198 199
  #define LIBGOLANG_DSO_EXPORT __attribute__ ((visibility ("default")))
  #define LIBGOLANG_DSO_IMPORT __attribute__ ((visibility ("default")))
#endif

#if BUILDING_LIBGOLANG
#  define LIBGOLANG_API LIBGOLANG_DSO_EXPORT
#else
#  define LIBGOLANG_API LIBGOLANG_DSO_IMPORT
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
#endif


// ---- C-level API that is always available ----
// (most of the functions are documented in libgolang.cpp)

#ifdef  __cplusplus
namespace golang {
extern "C" {
#endif

#ifdef __cplusplus
    [[noreturn]]
#else
    _Noreturn
#endif
LIBGOLANG_API void panic(const char *arg);
LIBGOLANG_API const char *recover(void);

Kirill Smelkov's avatar
Kirill Smelkov committed
219
LIBGOLANG_API void _taskgo(void (*f)(void *arg), void *arg);
Kirill Smelkov's avatar
Kirill Smelkov committed
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
typedef struct _chan _chan;
LIBGOLANG_API _chan *_makechan(unsigned elemsize, unsigned size);
LIBGOLANG_API void _chanxincref(_chan *ch);
LIBGOLANG_API void _chanxdecref(_chan *ch);
LIBGOLANG_API int  _chanrefcnt(_chan *ch);
LIBGOLANG_API void _chansend(_chan *ch, const void *ptx);
LIBGOLANG_API void _chanrecv(_chan *ch, void *prx);
LIBGOLANG_API bool _chanrecv_(_chan *ch, void *prx);
LIBGOLANG_API void _chanclose(_chan *ch);
LIBGOLANG_API unsigned _chanlen(_chan *ch);
LIBGOLANG_API unsigned _chancap(_chan *ch);

enum _chanop {
    _CHANSEND   = 0,
    _CHANRECV   = 1,
    _DEFAULT    = 2,
};

239 240 241 242 243 244 245 246 247
enum _selflags {
    // _INPLACE_DATA indicates that select case data is stored in
    // _selcase.itxrx instead of in *_selcase.ptxrx .
    // XXX can be used only for send for now. In the future, for symmetry, we
    // might want to allow _INPLACE_DATA for recv too.
    _INPLACE_DATA   = 1,
};


248 249
// _selcase represents one select case.
typedef struct _selcase {
250 251 252
    _chan           *ch;        // channel
    enum _chanop    op    : 8;  // chansend/chanrecv/default
    enum _selflags  flags : 8;  // e.g. _INPLACE_DATA
253 254 255
    unsigned        user  : 8;  // arbitrary value that can be set by user
                                // (e.g. pyselect stores channel type here)
    unsigned              : 8;
256 257 258 259 260
    union {
        void        *ptxrx;     // chansend: ptx; chanrecv: prx
        uint64_t     itxrx;     // used instead of .ptxrx if .flags&_INPLACE_DATA != 0
    };
    bool            *rxok;      // chanrecv: where to save ok if !NULL; otherwise not used
261 262 263 264 265 266 267 268 269 270

#ifdef __cplusplus
    // ptx returns pointer to data to send for this case.
    // .op must be _CHANSEND.
    LIBGOLANG_API const void *ptx() const;

    // prx returns pointer for this case to receive data into.
    // .op must be _CHANRECV.
    LIBGOLANG_API void *prx() const;
#endif
271 272 273 274 275 276 277 278 279 280
} _selcase;

LIBGOLANG_API int _chanselect(const _selcase *casev, int casec);

// _selsend creates `_chansend(ch, ptx)` case for _chanselect.
static inline
_selcase _selsend(_chan *ch, const void *ptx) {
    _selcase _ = {
        .ch     = ch,
        .op     = _CHANSEND,
281
        .flags  = (enum _selflags)0,
282
        .user   = 0xff,
283
    };
284 285
    _   .ptxrx  = (void *)ptx;
    _   .rxok   = NULL;
286 287 288 289 290 291 292 293 294
    return _;
}

// _selrecv creates `_chanrecv(ch, prx)` case for _chanselect.
static inline
_selcase _selrecv(_chan *ch, void *prx) {
    _selcase _ = {
        .ch     = ch,
        .op     = _CHANRECV,
295
        .flags  = (enum _selflags)0,
296
        .user   = 0xff,
297
    };
298 299
    _   .ptxrx  = prx;
    _   .rxok   = NULL;
300 301 302 303 304 305 306 307 308
    return _;
}

// _selrecv_ creates `*pok = _chanrecv_(ch, prx)` case for _chanselect.
static inline
_selcase _selrecv_(_chan *ch, void *prx, bool *pok) {
    _selcase _ = {
        .ch     = ch,
        .op     = _CHANRECV,
309
        .flags  = (enum _selflags)0,
310
        .user   = 0xff,
311
    };
312 313
    _   .ptxrx  = prx;
    _   .rxok   = pok;
314 315 316 317 318 319
    return _;
}

// _default represents default case for _chanselect.
extern LIBGOLANG_API const _selcase _default;

Kirill Smelkov's avatar
Kirill Smelkov committed
320 321

// libgolang runtime - the runtime must be initialized before any other libgolang use.
322
typedef struct _libgolang_sema _libgolang_sema;
Kirill Smelkov's avatar
Kirill Smelkov committed
323
typedef struct _libgolang_ioh  _libgolang_ioh;
324 325 326 327 328 329 330 331 332
typedef enum _libgolang_runtime_flags {
    // STACK_DEAD_WHILE_PARKED indicates that it is not safe to access
    // goroutine's stack memory while the goroutine is parked.
    //
    // for example gevent/greenlet/stackless use it because they copy g's stack
    // to heap on park and back on unpark. This way if objects on g's stack
    // were accessed while g was parked it would be memory of another g's stack.
    STACK_DEAD_WHILE_PARKED = 1,
} _libgolang_runtime_flags;
Kirill Smelkov's avatar
Kirill Smelkov committed
333
typedef struct _libgolang_runtime_ops {
334 335
    _libgolang_runtime_flags    flags;

Kirill Smelkov's avatar
Kirill Smelkov committed
336 337 338
    // go should spawn a task (coroutine/thread/...).
    void    (*go)(void (*f)(void *), void *arg);

339 340 341 342 343 344 345 346 347
    // sema_alloc should allocate a semaphore.
    // if allocation fails it must return NULL.
    _libgolang_sema* (*sema_alloc)(void);

    // sema_free should release previously allocated semaphore.
    // libgolang guarantees to call it only once and only for a semaphore
    // previously successfully allocated via sema_alloc.
    void             (*sema_free)   (_libgolang_sema*);

348 349 350 351 352 353 354
    // sema_acquire should try to acquire live semaphore allocated via sema_alloc during given time.
    // it returns whether acquisition succeeded or timed out.
    // the timeout is specified in nanoseconds.
    // UINT64_MAX means no timeout.
    bool             (*sema_acquire)(_libgolang_sema*, uint64_t timeout_ns);

    // sema_release should release live semaphore allocated via sema_alloc.
355 356
    void             (*sema_release)(_libgolang_sema*);

Kirill Smelkov's avatar
Kirill Smelkov committed
357 358 359 360 361 362 363
    // nanosleep should pause current goroutine for at least dt nanoseconds.
    // nanosleep(0) is not noop - such call must be at least yielding to other goroutines.
    void        (*nanosleep)(uint64_t dt);

    // nanotime should return current time since EPOCH in nanoseconds.
    uint64_t    (*nanotime)(void);

Kirill Smelkov's avatar
Kirill Smelkov committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    // ---- IO -----
    // NOTE syserr below is an error code always < 0, for example -ENOENT.

    // io_open should open file @path similarly to open(2), but the error is
    // returned in out_syserr, _not_ in errno.
    _libgolang_ioh* (*io_open) (int* out_syserr, const char *path, int flags, mode_t mode);

    // io_fdopen should wrap OS-level file descriptor into libgolang IO handle.
    // the ownership of sysfd is transferred to returned ioh.
    _libgolang_ioh* (*io_fdopen)(int* out_syserr, int sysfd);

    // io_close should close underlying file and release file resources
    // associated with ioh. it will be called exactly once and with the
    // guarantee that no other ioh operation is running durion io_close call.
    int/*syserr*/       (*io_close)(_libgolang_ioh* ioh);

    // io_free should release ioh memory.
    // it will be called exactly once after io_close.
    void                (*io_free) (_libgolang_ioh* ioh);

    // io_sysfd should return OS-level file descriptor associated with
    // libgolang IO handle. it should return -1 on error.
    int/*sysfd*/        (*io_sysfd) (_libgolang_ioh* ioh);

    // io_read should read up to count bytes of data from ioh.
    // it should block if waiting for at least some data is needed.
    // it should return read amount, 0 on EOF, or syserr on error.
    int/*(n|syserr)*/   (*io_read) (_libgolang_ioh* ioh, void *buf, size_t count);

    // io_write should write up to count bytes of data into ioh.
    // it should block if waiting is needed to write at least some data.
    // it should return wrote amount, or syserr on error.
    int/*(n|syserr)*/   (*io_write)(_libgolang_ioh* ioh, const void *buf, size_t count);

    // io_fstat should stat the file underlying ioh similarly to fstat(2).
    int/*syserr*/       (*io_fstat)(struct stat *out_st, _libgolang_ioh* ioh);

Kirill Smelkov's avatar
Kirill Smelkov committed
401 402 403 404 405
} _libgolang_runtime_ops;

LIBGOLANG_API void _libgolang_init(const _libgolang_runtime_ops *runtime_ops);


406 407 408 409 410
// for testing
LIBGOLANG_API int _tchanrecvqlen(_chan *ch);
LIBGOLANG_API int _tchansendqlen(_chan *ch);
LIBGOLANG_API extern void (*_tblockforever)(void);

411 412 413 414
#ifdef __cplusplus
}}
#endif

Kirill Smelkov's avatar
Kirill Smelkov committed
415 416 417 418 419

// ---- C++-level API that is available when compiling with C++ ----

#ifdef __cplusplus

420
#include <atomic>
421
#include <cstddef>
422
#include <exception>
Kirill Smelkov's avatar
Kirill Smelkov committed
423
#include <functional>
424
#include <initializer_list>
Kirill Smelkov's avatar
Kirill Smelkov committed
425
#include <memory>
426
#include <string>
427 428
#include <type_traits>
#include <utility>
429
#include <vector>
Kirill Smelkov's avatar
Kirill Smelkov committed
430

Kirill Smelkov's avatar
Kirill Smelkov committed
431 432
namespace golang {

433 434 435
// nil is alias for nullptr and NULL; Nil - for std::nullptr_t;
using Nil = std::nullptr_t;
constexpr Nil nil = nullptr;
436

437 438 439
// string is alias for std::string.
using string = std::string;

440 441 442 443
// byte/rune types related to string.
using byte = uint8_t;
using rune = int32_t;

444 445 446 447
// func is alias for std::function.
template<typename F>
using func = std::function<F>;

Kirill Smelkov's avatar
Kirill Smelkov committed
448
// go provides type-safe wrapper over _taskgo.
449 450 451
template<typename F, typename... Argv>  // F = func<void(Argv...)>
static inline void go(F /*func<void(Argv...)>*/ f, Argv... argv) {
    typedef func<void()> Frun;
Kirill Smelkov's avatar
Kirill Smelkov committed
452 453 454 455 456 457 458 459
    Frun *frun = new Frun (std::bind(f, argv...));
    _taskgo([](void *_frun) {
        std::unique_ptr<Frun> frun (reinterpret_cast<Frun*>(_frun));
        (*frun)();
        // frun deleted here on normal exit or panic.
    }, frun);
}

460 461
template<typename T> class chan;
template<typename T> static chan<T> makechan(unsigned size=0);
462
template<typename T> static chan<T> _wrapchan(_chan *_ch);
463 464 465 466 467 468 469 470 471 472

// chan<T> provides type-safe wrapper over _chan.
//
// chan<T> is automatically reference-counted and is safe to use from multiple
// goroutines simultaneously.
template<typename T>
class chan {
    _chan *_ch;

public:
473
    inline chan() { _ch = nil; } // nil channel if not explicitly initialized
474
    friend chan<T> makechan<T>(unsigned size);
475
    friend chan<T> _wrapchan<T>(_chan *_ch);
476
    inline ~chan() { _chanxdecref(_ch); _ch = nil; }
477 478

    // = nil
479 480
    inline chan(Nil) { _ch = nil; }
    inline chan& operator=(Nil) { _chanxdecref(_ch); _ch = nil; return *this; }
481 482 483 484 485 486 487 488 489
    // copy
    inline chan(const chan& from) { _ch = from._ch; _chanxincref(_ch); }
    inline chan& operator=(const chan& from) {
        if (this != &from) {
            _chanxdecref(_ch); _ch = from._ch; _chanxincref(_ch);
        }
        return *this;
    }
    // move
490
    inline chan(chan&& from) { _ch = from._ch; from._ch = nil; }
491 492
    inline chan& operator=(chan&& from) {
        if (this != &from) {
493
            _chanxdecref(_ch); _ch = from._ch; from._ch = nil;
494 495 496 497 498 499 500 501 502
        }
        return *this;
    }

    // _chan does plain memcpy to copy elements.
    // TODO allow all types (e.g. element=chan )
    static_assert(std::is_trivially_copyable<T>::value, "TODO chan<T>: T copy is not trivial");

    // send/recv/close
503 504 505 506 507
    inline void send(const T &ptx)    const  { _chansend(_ch, &ptx);                  }
    inline T recv()                   const  { T rx; _chanrecv(_ch, &rx); return rx;  }
    inline std::pair<T,bool> recv_()  const  { T rx; bool ok = _chanrecv_(_ch, &rx);
                                               return std::make_pair(rx, ok);         }
    inline void close()               const  { _chanclose(_ch);                       }
508 509 510 511

    // send/recv in select

    // ch.sends creates `ch.send(*ptx)` case for select.
512
    [[nodiscard]] inline _selcase sends(const T *ptx) const { return _selsend(_ch, ptx); }
513 514 515 516 517

    // ch.recvs creates `*prx = ch.recv()` case for select.
    //
    // if pok is provided the case is extended to `[*prx, *pok] = ch.recv_()`
    // if both prx and pok are omitted the case is reduced to `ch.recv()`.
518
    [[nodiscard]] inline _selcase recvs(T *prx=nil, bool *pok=nil) const {
519 520 521 522
        return _selrecv_(_ch, prx, pok);
    }

    // length/capacity
523 524
    inline unsigned len()       const  { return _chanlen(_ch); }
    inline unsigned cap()       const  { return _chancap(_ch); }
525 526

    // compare wrt nil
527 528
    inline bool operator==(Nil) const  { return (_ch == nil); }
    inline bool operator!=(Nil) const  { return (_ch != nil); }
529 530

    // compare wrt chan
531 532
    inline bool operator==(const chan<T>& ch2) const { return (_ch == ch2._ch); }
    inline bool operator!=(const chan<T>& ch2) const { return (_ch != ch2._ch); }
533 534

    // for testing
535
    inline _chan *_rawchan() const     { return _ch; }
536 537
};

538 539 540 541 542 543 544 545
// _elemsize<T> returns element size for chan<T>.
template<typename T> static inline
unsigned _elemsize() {
    return std::is_empty<T>::value
        ? 0          // eg struct{} for which sizeof() gives 1 - *not* 0
        : sizeof(T);
}

546 547 548 549
// makechan<T> makes new chan<T> with capacity=size.
template<typename T> static inline
chan<T> makechan(unsigned size) {
    chan<T> ch;
550 551 552 553 554
    ch._ch = _makechan(_elemsize<T>(), size);
    return ch;
}

// _wrapchan<T> wraps raw channel with chan<T>.
555
// raw channel must be either nil or its element size must correspond to T.
556 557 558 559 560 561
LIBGOLANG_API void __wrapchan(_chan *_ch, unsigned elemsize);
template<typename T> static inline
chan<T> _wrapchan(_chan *_ch) {
    chan<T> ch;
    __wrapchan(_ch, _elemsize<T>());
    ch._ch = _ch;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
    return ch;
}

// structZ is struct{}.
//
// it's a workaround for e.g. makechan<struct{}> giving
// "error: types may not be defined in template arguments".
struct structZ{};

// select, together with chan<T>.sends and chan<T>.recvs, provide type-safe
// wrappers over _chanselect and _selsend/_selrecv/_selrecv_.
//
// Usage example:
//
//   _ = select({
//       ch1.recvs(&v),         // 0
//       ch2.recvs(&v, &ok),    // 1
//       ch2.sends(&v),         // 2
//       _default,              // 3
//   })
static inline                       // select({case1, case2, case3})
int select(const std::initializer_list<const _selcase> &casev) {
    return _chanselect(casev.begin(), casev.size());
}

template<size_t N> static inline    // select(casev_array)
int select(const _selcase (&casev)[N]) {
    return _chanselect(&casev[0], N);
}

592 593
static inline                       // select(vector<casev>)
int select(const std::vector<_selcase> &casev) {
594
    return _chanselect(casev.data(), casev.size());
595 596
}

597 598
// defer(f) mimics `defer f()` from golang.
// NOTE contrary to Go f is called at end of current scope, not function.
599 600 601
#define defer(f) golang::_deferred _defer_(__COUNTER__) (f)
#define _defer_(counter)    _defer_2(counter)
#define _defer_2(counter)   _defer_##counter
602
struct _deferred {
603
    typedef func<void()> F;
604 605 606 607 608 609 610 611 612
    F f;

    _deferred(F f) : f(f) {}
    ~_deferred() { f(); }
private:
    _deferred(const _deferred&);    // don't copy
    _deferred(_deferred&&);         // don't move
};

Kirill Smelkov's avatar
Kirill Smelkov committed
613

614 615 616 617 618 619 620
// ---- reference-counted objects ----
// C++ does not have garbage-collector -> libgolang provides illusion of GC
// via reference counting support.

template<typename T> class refptr;
template<typename T> refptr<T> adoptref(T *_obj);
template<typename T> refptr<T> newref  (T *_obj);
621
template<typename R> class global;
622 623 624

// refptr<T> is smart pointer to T which manages T lifetime via reference counting.
//
625
// T must provide incref/decref methods for example via inheriting from object.
626
// incref/decref must be safe to use from multiple threads simultaneously.
627 628
//
// See also interface.
629 630 631 632
template<typename T>
class refptr {
    T *_obj;

633 634 635
    typedef T obj_type;
    friend global<refptr<T>>;

636 637
public:
    // nil if not explicitly initialized
638
    inline refptr()                 { _obj = nil;  }
639 640

    inline ~refptr() {
641
        if (_obj != nil) {
642
            _obj->decref();
643
            _obj = nil;
644 645 646 647
        }
    }

    // = nil
648 649
    inline refptr(Nil)              { _obj = nil;  }
    inline refptr& operator=(Nil) {
650
        if (_obj != nil)
651
            _obj->decref();
652
        _obj = nil;
653 654 655 656 657 658
        return *this;
    }

    // copy
    inline refptr(const refptr& from) {
        _obj = from._obj;
659
        if (_obj != nil)
660 661 662 663
            _obj->incref();
    }
    inline refptr& operator=(const refptr& from) {
        if (this != &from) {
664
            if (_obj != nil)
665 666
                _obj->decref();
            _obj = from._obj;
667
            if (_obj != nil)
668 669 670 671 672 673 674 675
                _obj->incref();
        }
        return *this;
    }

    // move
    inline refptr(refptr&& from) {
        _obj = from._obj;
676
        from._obj = nil;
677 678 679
    }
    inline refptr& operator=(refptr&& from) {
        if (this != &from) {
680
            if (_obj != nil)
681 682
                _obj->decref();
            _obj = from._obj;
683
            from._obj = nil;
684 685 686 687 688 689 690 691 692
        }
        return *this;
    }

    // create from raw pointer
    friend refptr<T> adoptref<T>(T *_obj);
    friend refptr<T> newref<T>  (T *_obj);

    // compare wrt nil
693 694
    inline bool operator==(Nil) const { return (_obj == nil); }
    inline bool operator!=(Nil) const { return (_obj != nil); }
695 696 697 698 699 700 701 702 703 704 705 706 707

    // compare wrt refptr
    inline bool operator==(const refptr& p2) const { return (_obj == p2._obj);  }
    inline bool operator!=(const refptr& p2) const { return (_obj != p2._obj);  }

    // dereference, so that e.g. p->method() automatically works as p._obj->method().
    inline T* operator-> () const   { return _obj;  }
    inline T& operator*  () const   { return *_obj; }

    // access to raw pointer
    inline T *_ptr() const          { return _obj;  }
};

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
// global<refptr<T>> is like refptr<T> but does not deallocate the object on pointer destruction.
//
// The sole reason for global to exist is to avoid race condition on program exit
// when global refptr<T> pointer is destructed, but another thread that
// continues to run, accesses the pointer.
//
// global<X> should be interoperable where X is used, for example:
//
//      const global<error> ErrSomething = errors::New("abc")
//      error err = ...;
//      if (err == ErrSomething)
//          ...
template<typename R>
class global {
    // implementation note:
    //  - don't use base parent for refptr and global with common functionality
    //    in parent, because e.g. copy-constructors cannot-be inherited.
    //  - don't use _refptr<T, bool global> template not to make compiler error
    //    messages longer for common refptr<T> case.
    //
    // -> just mimic refptr<T> functionality with a bit of duplication.
    typedef typename R::obj_type T;
    T *_obj;

public:
    // global does not release reference to its object, nor clears ._obj
    inline ~global() {}

    // cast global<refptr<T>> -> to refptr<T>
    operator refptr<T> () const {
        return newref<T>(_obj);
    }

    // nil if not explicitly initialized
742
    inline global()                 { _obj = nil;   }
743 744 745 746

    // init from refptr<T>
    inline global(const refptr<T>& from) {
        _obj = from._obj;
747
        if (_obj != nil)
748 749 750 751
            _obj->incref();
    }

    // = nil
752 753
    inline global(Nil)              { _obj = nil;   }
    inline global& operator=(Nil) {
754
        if (_obj != nil)
755
            _obj->decref();
756
        _obj = nil;
757 758 759 760 761 762 763
        return *this;
    }

    // copy - no need due to refptr<T> cast
    // move - no need due to refptr<T> cast

    // compare wrt nil
764 765
    inline bool operator==(Nil) const { return (_obj == nil); }
    inline bool operator!=(Nil) const { return (_obj != nil); }
766 767 768 769 770 771 772 773 774 775 776 777 778

    // compare wrt refptr
    inline bool operator==(const refptr<T>& p2) const { return (_obj == p2._obj);  }
    inline bool operator!=(const refptr<T>& p2) const { return (_obj != p2._obj);  }

    // dereference, so that e.g. p->method() automatically works as p._obj->method().
    inline T* operator-> () const   { return _obj;  }
    inline T& operator*  () const   { return *_obj; }

    // access to raw pointer
    inline T *_ptr() const          { return _obj;  }
};

779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
// adoptref wraps raw T* pointer into refptr<T> and transfers object ownership to it.
//
// The object is assumed to have reference 1 initially.
// Usage example:
//
//      refptr<MyClass> p = adoptref(new MyClass());
//      ...
//      // the object will be deleted when p goes out of scope
template<typename T>
inline refptr<T> adoptref(T *_obj) {
    refptr<T> p;
    p._obj = _obj;
    return p;
}

// newref wraps raw T* pointer into refptr<T>.
//
// Created refptr holds new reference onto wrapped object.
// Usage example:
//
//      doSomething(MyClass *obj) {
//          refptr<MyClass> p = newref(obj);
//          ...
//          // obj is guaranteed to stay alive until p stays alive
//      }
template<typename T>
inline refptr<T> newref(T *_obj) {
    refptr<T> p;
    p._obj = _obj;
808
    if (_obj != nil)
809 810 811 812
        _obj->incref();
    return p;
}

813
// object is the base-class for on-heap objects.
814
//
815 816 817 818
// It provides reference-counting functionality, which, when used via refptr,
// provides automatic memory management for allocated objects.
//
// object provides incref & __decref - the user must implement decref(*).
819 820
//
// (*) this way we don't require destructor to be virtual.
821
class object {
822 823 824
    std::atomic<int> _refcnt;    // reference counter for the object

protected:
825 826
    LIBGOLANG_API object();
    LIBGOLANG_API ~object();
827 828 829 830 831 832 833
    LIBGOLANG_API bool __decref();

public:
    LIBGOLANG_API void incref();
    LIBGOLANG_API int  refcnt() const;
};

834 835 836 837 838 839 840 841 842 843 844 845
// interface is empty interface a-la interface{} in Go.
//
// It is the base class of all interfaces.
//
// Even if the interface is empty, it requires memory-management methods to be
// present. See refptr for details.
struct _interface {
    virtual void incref() = 0;
    virtual void decref() = 0;

protected:
    // don't use destructor -> use decref
846
    LIBGOLANG_API ~_interface();
847 848 849 850 851 852
};
typedef refptr<_interface> interface;


// error is the interface describing errors.
struct _error : _interface {
853
    virtual string Error() = 0;
854 855
};
typedef refptr<_error> error;
856

857 858 859 860 861 862
// an error can additionally provide Unwrap method if it wraps another error.
struct _errorWrapper : _error {
    virtual error Unwrap() = 0;
};
typedef refptr<_errorWrapper> errorWrapper;

Kirill Smelkov's avatar
Kirill Smelkov committed
863
}   // golang::
864 865


866
// std::
867 868
namespace std {

869
// std::hash<refptr>
870 871 872 873 874 875
template<typename T> struct hash<golang::refptr<T>> {
    std::size_t operator()(const golang::refptr<T>& p) const noexcept {
        return hash<T*>()(p._ptr());
    }
};

876 877 878 879 880 881 882
// std::hash<chan>
template<typename T> struct hash<golang::chan<T>> {
    std::size_t operator()(const golang::chan<T>& ch) const noexcept {
        return hash<void*>()(reinterpret_cast<void*>(ch._rawchan()));
    }
};

883 884 885
}   // std::


Kirill Smelkov's avatar
Kirill Smelkov committed
886 887
#endif  // __cplusplus

888
#endif  // _NXD_LIBGOLANG_H